diff --git a/DEPS b/DEPS
index 00ef99c..7645272 100644
--- a/DEPS
+++ b/DEPS
@@ -185,7 +185,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'b28ca6f38f9b637fd639be49546867e07bcaa0ac',
+  'v8_revision': '4cde67a85fd4c29f78551e5aebca1fc8912876e8',
   # 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.
@@ -201,7 +201,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling PDFium
   # and whatever else without interference from each other.
-  'pdfium_revision': 'fcb6cd6d22a279c076217dcbb3154106fa5fd5d9',
+  'pdfium_revision': 'c3e55aa23f888aaf9334a3fd35c1f49a3179869c',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling BoringSSL
   # and whatever else without interference from each other.
@@ -252,7 +252,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': 'b5315e84d143e54e0238299709f208d36e4b4e57',
+  'devtools_frontend_revision': '564dcf4c071b93382616e9421610aa2ac655a833',
   # 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.
@@ -312,7 +312,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': '3003aa622b2fc452a66707922b99a64f89b84bce',
+  'dawn_revision': '80880ee9985484d39355d2827ce5cb9343a07e91',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -544,7 +544,7 @@
   },
 
   'src/ios/third_party/material_font_disk_loader_ios/src': {
-      'url': Var('chromium_git') + '/external/github.com/material-foundation/material-font-disk-loader-ios.git' + '@' + '93acc021e3034898716028822cb802a3a816be7e',
+      'url': Var('chromium_git') + '/external/github.com/material-foundation/material-font-disk-loader-ios.git' + '@' + '8e30188777b016182658fbaa0a4a020a48183224',
       'condition': 'checkout_ios',
   },
 
@@ -690,7 +690,7 @@
       'packages': [
           {
               'package': 'chromium/third_party/android_build_tools/aapt2',
-              'version': 'TM6ESkOFwhdEwjsIxbY3m6j7BIhg8mpY_X9Pg0nwb1AC',
+              'version': 'LKH_DI44rZhQ4RkScMFQLGSJ4jZyuPcff0llITnq-i4C',
           },
       ],
       'condition': 'checkout_android',
@@ -1571,7 +1571,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@8f5aa560c98d070293830e4a9272957f5428263e',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@6b41dac7d03098e0482bf9cafa84c60683d20372',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index 9857a9f..f64714a 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1824,6 +1824,7 @@
     "session/session_controller_impl_unittest.cc",
     "shelf/back_button_unittest.cc",
     "shelf/home_button_unittest.cc",
+    "shelf/hotseat_widget_unittest.cc",
     "shelf/login_shelf_view_unittest.cc",
     "shelf/scrollable_shelf_view_unittest.cc",
     "shelf/shelf_application_menu_model_unittest.cc",
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc
index 79edc96..9f9a7477 100644
--- a/ash/app_list/app_list_controller_impl.cc
+++ b/ash/app_list/app_list_controller_impl.cc
@@ -530,7 +530,7 @@
 
   // Hide app list UI initially to prevent app list from flashing in background
   // while the initial app window is being shown.
-  if (!last_target_visible_)
+  if (!last_target_visible_ && !ShouldHomeLauncherBeVisible())
     presenter_.SetViewVisibility(false);
   else
     OnVisibilityChanged(true, last_visible_display_id_);
diff --git a/ash/public/cpp/assistant/assistant_state_base.cc b/ash/public/cpp/assistant/assistant_state_base.cc
index c209503..adf9d9b2 100644
--- a/ash/public/cpp/assistant/assistant_state_base.cc
+++ b/ash/public/cpp/assistant/assistant_state_base.cc
@@ -30,7 +30,10 @@
 
 AssistantStateBase::AssistantStateBase() = default;
 
-AssistantStateBase::~AssistantStateBase() = default;
+AssistantStateBase::~AssistantStateBase() {
+  for (auto& observer : observers_)
+    observer.OnAssistantStateDestroyed();
+}
 
 std::string AssistantStateBase::ToString() const {
   std::stringstream result;
diff --git a/ash/public/cpp/assistant/assistant_state_base.h b/ash/public/cpp/assistant/assistant_state_base.h
index ebbfb14..b929e472 100644
--- a/ash/public/cpp/assistant/assistant_state_base.h
+++ b/ash/public/cpp/assistant/assistant_state_base.h
@@ -35,6 +35,7 @@
   virtual void OnAssistantHotwordEnabled(bool enabled) {}
   virtual void OnAssistantLaunchWithMicOpen(bool launch_with_mic_open) {}
   virtual void OnAssistantNotificationEnabled(bool notification_enabled) {}
+  virtual void OnAssistantStateDestroyed() {}
 
   // mojom::AssistantStateObserver:
   void OnAssistantStatusChanged(mojom::AssistantState state) override {}
diff --git a/ash/shelf/hotseat_widget_unittest.cc b/ash/shelf/hotseat_widget_unittest.cc
new file mode 100644
index 0000000..20d28fc
--- /dev/null
+++ b/ash/shelf/hotseat_widget_unittest.cc
@@ -0,0 +1,180 @@
+// Copyright (c) 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/app_list/app_list_controller_impl.h"
+#include "ash/app_list/test/app_list_test_helper.h"
+#include "ash/shelf/shelf.h"
+#include "ash/shelf/shelf_app_button.h"
+#include "ash/shelf/shelf_layout_manager.h"
+#include "ash/shelf/shelf_test_util.h"
+#include "ash/shelf/shelf_view.h"
+#include "ash/shelf/shelf_view_test_api.h"
+#include "ash/shell.h"
+#include "ash/test/ash_test_base.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
+#include "base/test/scoped_feature_list.h"
+#include "chromeos/constants/chromeos_features.h"
+#include "ui/events/gesture_detection/gesture_configuration.h"
+#include "ui/events/test/event_generator.h"
+#include "ui/wm/core/window_util.h"
+
+namespace ash {
+
+namespace {
+ShelfLayoutManager* GetShelfLayoutManager() {
+  return AshTestBase::GetPrimaryShelf()->shelf_layout_manager();
+}
+}  // namespace
+
+class HotseatWidgetTest
+    : public AshTestBase,
+      public testing::WithParamInterface<ShelfAutoHideBehavior> {
+ public:
+  HotseatWidgetTest() = default;
+
+  // Performs a swipe up gesture to show an auto-hidden shelf.
+  void SwipeUpOnShelf() {
+    gfx::Rect display_bounds =
+        display::Screen::GetScreen()->GetPrimaryDisplay().bounds();
+    const gfx::Point start(display_bounds.bottom_center());
+    const gfx::Point end(start + gfx::Vector2d(0, -80));
+    const base::TimeDelta kTimeDelta = base::TimeDelta::FromMilliseconds(100);
+    const int kNumScrollSteps = 4;
+    GetEventGenerator()->GestureScrollSequence(start, end, kTimeDelta,
+                                               kNumScrollSteps);
+  }
+
+  void SwipeDownOnShelf() {
+    gfx::Point start(GetPrimaryShelf()
+                         ->shelf_widget()
+                         ->shelf_view_for_testing()
+                         ->GetBoundsInScreen()
+                         .top_center());
+    const gfx::Point end(start + gfx::Vector2d(0, 40));
+    const base::TimeDelta kTimeDelta = base::TimeDelta::FromMilliseconds(100);
+    const int kNumScrollSteps = 4;
+    GetEventGenerator()->GestureScrollSequence(start, end, kTimeDelta,
+                                               kNumScrollSteps);
+  }
+
+ private:
+  base::test::ScopedFeatureList scoped_feature_list_;
+};
+
+// Used to test the Hotseat, ScrollabeShelf, and DenseShelf features.
+INSTANTIATE_TEST_SUITE_P(All,
+                         HotseatWidgetTest,
+                         testing::Values(ShelfAutoHideBehavior::kNever,
+                                         ShelfAutoHideBehavior::kAlways));
+
+// Tests that closing a window which was opened prior to entering tablet mode
+// results in a kShown hotseat.
+TEST_P(HotseatWidgetTest, ClosingLastWindowInTabletMode) {
+  GetPrimaryShelf()->SetAutoHideBehavior(GetParam());
+  std::unique_ptr<aura::Window> window =
+      AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400));
+  // Activate the window and go to tablet mode.
+  wm::ActivateWindow(window.get());
+  TabletModeControllerTestApi().EnterTabletMode();
+
+  // Close the window, the AppListView should be shown, and the hotseat should
+  // be kShown.
+  window->Hide();
+
+  EXPECT_EQ(HotseatState::kShown, GetShelfLayoutManager()->hotseat_state());
+  GetAppListTestHelper()->CheckVisibility(true);
+}
+
+// Tests that the hotseat is kShown when entering tablet mode with no windows.
+TEST_P(HotseatWidgetTest, GoingToTabletModeNoWindows) {
+  GetPrimaryShelf()->SetAutoHideBehavior(GetParam());
+  TabletModeControllerTestApi().EnterTabletMode();
+
+  GetAppListTestHelper()->CheckVisibility(true);
+  EXPECT_EQ(HotseatState::kShown, GetShelfLayoutManager()->hotseat_state());
+}
+
+// Tests that the hotseat is kHidden when entering tablet mode with a window.
+TEST_P(HotseatWidgetTest, GoingToTabletModeWithWindows) {
+  GetPrimaryShelf()->SetAutoHideBehavior(GetParam());
+
+  std::unique_ptr<aura::Window> window =
+      AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400));
+  // Activate the window and go to tablet mode.
+  wm::ActivateWindow(window.get());
+  TabletModeControllerTestApi().EnterTabletMode();
+
+  EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state());
+  GetAppListTestHelper()->CheckVisibility(false);
+}
+
+// The in-app Hotseat should not be hidden automatically when the shelf context
+// menu shows (https://crbug.com/1020388).
+TEST_P(HotseatWidgetTest, InAppShelfShowingContextMenu) {
+  GetPrimaryShelf()->SetAutoHideBehavior(GetParam());
+  TabletModeControllerTestApi().EnterTabletMode();
+  std::unique_ptr<aura::Window> window =
+      AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400));
+  wm::ActivateWindow(window.get());
+  EXPECT_FALSE(Shell::Get()->app_list_controller()->IsVisible());
+
+  ShelfTestUtil::AddAppShortcut("app_id", TYPE_PINNED_APP);
+
+  // Swipe up on the shelf to show the hotseat.
+  SwipeUpOnShelf();
+  EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state());
+
+  ShelfViewTestAPI shelf_view_test_api(
+      GetPrimaryShelf()->shelf_widget()->shelf_view_for_testing());
+  ShelfAppButton* app_icon = shelf_view_test_api.GetButton(0);
+
+  // Accelerate the generation of the long press event.
+  ui::GestureConfiguration::GetInstance()->set_show_press_delay_in_ms(1);
+  ui::GestureConfiguration::GetInstance()->set_long_press_time_in_ms(1);
+
+  // Press the icon enough long time to generate the long press event.
+  GetEventGenerator()->MoveTouch(app_icon->GetBoundsInScreen().CenterPoint());
+  GetEventGenerator()->PressTouch();
+  ui::GestureConfiguration* gesture_config =
+      ui::GestureConfiguration::GetInstance();
+  const int long_press_delay_ms = gesture_config->long_press_time_in_ms() +
+                                  gesture_config->show_press_delay_in_ms();
+  base::RunLoop run_loop;
+  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
+      FROM_HERE, run_loop.QuitClosure(),
+      base::TimeDelta::FromMilliseconds(long_press_delay_ms));
+  run_loop.Run();
+  GetEventGenerator()->ReleaseTouch();
+
+  // Expects that the hotseat's state is kExntended.
+  EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state());
+
+  // Ensures that the ink drop state is InkDropState::ACTIVATED before closing
+  // the menu.
+  app_icon->FireRippleActivationTimerForTest();
+}
+
+// Tests that a window that is created after going to tablet mode, then closed,
+// results in a kShown hotseat.
+TEST_P(HotseatWidgetTest, CloseLastWindowOpenedInTabletMode) {
+  GetPrimaryShelf()->SetAutoHideBehavior(GetParam());
+  TabletModeControllerTestApi().EnterTabletMode();
+
+  std::unique_ptr<aura::Window> window =
+      AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400));
+  // Activate the window after entering tablet mode.
+  wm::ActivateWindow(window.get());
+
+  EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state());
+  GetAppListTestHelper()->CheckVisibility(false);
+
+  // Hide the window, the hotseat should be kShown, and the home launcher should
+  // be visible.
+  window->Hide();
+
+  EXPECT_EQ(HotseatState::kShown, GetShelfLayoutManager()->hotseat_state());
+  GetAppListTestHelper()->CheckVisibility(true);
+}
+
+}  // namespace ash
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index e3d708c..6f87938 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -2148,7 +2148,10 @@
   if (Shell::Get()->app_list_controller()->IsVisible())
     return true;
 
-  return StartShelfDrag(gesture_in_screen);
+  return StartShelfDrag(
+      gesture_in_screen,
+      gfx::Vector2dF(gesture_in_screen.details().scroll_x_hint(),
+                     scroll_y_hint));
 }
 
 void ShelfLayoutManager::UpdateGestureDrag(
@@ -2183,7 +2186,10 @@
 void ShelfLayoutManager::StartMouseDrag(const ui::MouseEvent& mouse_in_screen) {
   float scroll_y_hint = mouse_in_screen.y() - last_mouse_drag_position_.y();
   if (!StartAppListDrag(mouse_in_screen, scroll_y_hint))
-    StartShelfDrag(mouse_in_screen);
+    StartShelfDrag(
+        mouse_in_screen,
+        gfx::Vector2dF(mouse_in_screen.x() - last_mouse_drag_position_.x(),
+                       scroll_y_hint));
 }
 
 void ShelfLayoutManager::UpdateMouseDrag(
@@ -2304,8 +2310,8 @@
   return true;
 }
 
-bool ShelfLayoutManager::StartShelfDrag(
-    const ui::LocatedEvent& event_in_screen) {
+bool ShelfLayoutManager::StartShelfDrag(const ui::LocatedEvent& event_in_screen,
+                                        const gfx::Vector2dF& scroll_hint) {
   // Disable the shelf dragging if the fullscreen app list is opened.
   if (Shell::Get()->app_list_controller()->IsVisible() &&
       !IsTabletModeEnabled())
@@ -2343,6 +2349,13 @@
     drag_amount_ = 0.f;
   }
 
+  // If the start location is above the shelf (e.g., on the extended hotseat),
+  // do not allow window drag when the hotseat is extended.
+  const gfx::Rect shelf_bounds = GetVisibleShelfBounds();
+  allow_window_drag_on_extended_hotseat_ =
+      event_in_screen.location_f().y() >= shelf_bounds.y();
+
+  MaybeStartDragWindowFromShelf(event_in_screen, scroll_hint);
   return true;
 }
 
@@ -2653,8 +2666,6 @@
   if (hotseat_state() == HotseatState::kShown)
     return false;
 
-  gfx::PointF event_start_location = event_in_screen.location_f();
-
   // If hotseat is hidden when drag starts, do not start drag window if hotseat
   // hasn't been fully dragged up.
   if (hotseat_state() == HotseatState::kHidden) {
@@ -2665,16 +2676,9 @@
     if (drag_amount_ > full_drag_amount)
       return false;
   } else if (hotseat_state() == HotseatState::kExtended) {
-    // Window drag will not start until it's determined that the gesture is
-    // going up. The effective starting position will thus be the previous event
-    // location.
-    event_start_location -= scroll;
-
-    // If the start location is above the shelf (e.g., on the extended hotseat),
-    // do not allow the drag.
-    const gfx::Rect shelf_bounds = GetVisibleShelfBounds();
-    if (event_start_location.y() < shelf_bounds.y())
+    if (!allow_window_drag_on_extended_hotseat_)
       return false;
+
     // Do not start drag if it's a downward update event.
     if (scroll.y() >= 0)
       return false;
@@ -2693,15 +2697,7 @@
     return false;
 
   window_drag_controller_ = std::make_unique<DragWindowFromShelfController>(
-      window, event_start_location, hotseat_state());
-
-  // In extended state, the effective start location is the previous event, so
-  // send additional drag event, so the controller doesn't skip the current
-  // drag location.
-  if (hotseat_state() == HotseatState::kExtended) {
-    window_drag_controller_->Drag(event_in_screen.location_f(), scroll.x(),
-                                  scroll.y());
-  }
+      window, event_in_screen.location_f(), hotseat_state());
   return true;
 }
 
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index 96370f77..b526e89 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -502,7 +502,8 @@
   bool IsDragAllowed() const;
   bool StartAppListDrag(const ui::LocatedEvent& event_in_screen,
                         float scroll_y_hint);
-  bool StartShelfDrag(const ui::LocatedEvent& event_in_screen);
+  bool StartShelfDrag(const ui::LocatedEvent& event_in_screen,
+                      const gfx::Vector2dF& scroll_hint);
   // Sets the Hotseat up to be dragged, if applicable.
   void MaybeSetupHotseatDrag(const ui::LocatedEvent& event_in_screen);
   void UpdateDrag(const ui::LocatedEvent& event_in_screen,
@@ -692,6 +693,11 @@
   // if the overview session is active.
   bool allow_fling_from_overview_to_home_ = false;
 
+  // Indicates whether shelf drag gesture can start window drag from shelf to
+  // overview or home when hotseat is in extended state (the window drag will
+  // only be allowed if drag started within shelf bounds).
+  bool allow_window_drag_on_extended_hotseat_ = false;
+
   // Tracks whether the shelf is currently dimmed for inactivity.
   bool dimmed_for_inactivity_ = false;
 
diff --git a/ash/shelf/shelf_layout_manager_unittest.cc b/ash/shelf/shelf_layout_manager_unittest.cc
index a5d8345d..ba109ad 100644
--- a/ash/shelf/shelf_layout_manager_unittest.cc
+++ b/ash/shelf/shelf_layout_manager_unittest.cc
@@ -3372,69 +3372,6 @@
                          testing::Values(ShelfAutoHideBehavior::kNever,
                                          ShelfAutoHideBehavior::kAlways));
 
-// Tests that the hotseat is kShown when entering tablet mode with no windows.
-TEST_P(HotseatShelfLayoutManagerTest, GoingToTabletModeNoWindows) {
-  GetPrimaryShelf()->SetAutoHideBehavior(GetParam());
-  TabletModeControllerTestApi().EnterTabletMode();
-
-  GetAppListTestHelper()->CheckVisibility(true);
-  EXPECT_EQ(HotseatState::kShown, GetShelfLayoutManager()->hotseat_state());
-}
-
-// Tests that the hotseat is kHidden when entering tablet mode with a window.
-TEST_P(HotseatShelfLayoutManagerTest, GoingToTabletModeWithWindows) {
-  GetPrimaryShelf()->SetAutoHideBehavior(GetParam());
-
-  std::unique_ptr<aura::Window> window =
-      AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400));
-  // Activate the window and go to tablet mode.
-  wm::ActivateWindow(window.get());
-  TabletModeControllerTestApi().EnterTabletMode();
-
-  EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state());
-  GetAppListTestHelper()->CheckVisibility(false);
-}
-
-// Tests that closing a window which was opened prior to entering tablet mode
-// results in a kShown hotseat.
-TEST_P(HotseatShelfLayoutManagerTest, ClosingLastWindowInTabletMode) {
-  GetPrimaryShelf()->SetAutoHideBehavior(GetParam());
-  std::unique_ptr<aura::Window> window =
-      AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400));
-  // Activate the window and go to tablet mode.
-  wm::ActivateWindow(window.get());
-  TabletModeControllerTestApi().EnterTabletMode();
-
-  // Close the window, the AppListView should be shown, and the hotseat should
-  // be kShown.
-  window->Hide();
-
-  EXPECT_EQ(HotseatState::kShown, GetShelfLayoutManager()->hotseat_state());
-  GetAppListTestHelper()->CheckVisibility(true);
-}
-
-// Tests that a window that is created after going to tablet mode, then closed,
-// results in a kShown hotseat.
-TEST_P(HotseatShelfLayoutManagerTest, CloseLastWindowOpenedInTabletMode) {
-  GetPrimaryShelf()->SetAutoHideBehavior(GetParam());
-  TabletModeControllerTestApi().EnterTabletMode();
-
-  std::unique_ptr<aura::Window> window =
-      AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400));
-  // Activate the window after entering tablet mode.
-  wm::ActivateWindow(window.get());
-
-  EXPECT_EQ(HotseatState::kHidden, GetShelfLayoutManager()->hotseat_state());
-  GetAppListTestHelper()->CheckVisibility(false);
-
-  // Hide the window, the hotseat should be kShown, and the home launcher should
-  // be visible.
-  window->Hide();
-
-  EXPECT_EQ(HotseatState::kShown, GetShelfLayoutManager()->hotseat_state());
-  GetAppListTestHelper()->CheckVisibility(true);
-}
-
 // Tests that swiping up on an autohidden shelf shows the hotseat, and swiping
 // down hides it.
 TEST_F(HotseatShelfLayoutManagerTest, ShowingAndHidingAutohiddenShelf) {
@@ -3546,52 +3483,6 @@
                                      InAppShelfGestures::kSwipeUpToShow, 3);
 }
 
-// The in-app Hotseat should not be hidden automatically when the shelf context
-// menu shows (https://crbug.com/1020388).
-TEST_P(HotseatShelfLayoutManagerTest, InAppShelfShowingContextMenu) {
-  GetPrimaryShelf()->SetAutoHideBehavior(GetParam());
-  TabletModeControllerTestApi().EnterTabletMode();
-  std::unique_ptr<aura::Window> window =
-      AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400));
-  wm::ActivateWindow(window.get());
-  EXPECT_FALSE(Shell::Get()->app_list_controller()->IsVisible());
-
-  ShelfTestUtil::AddAppShortcut("app_id", TYPE_PINNED_APP);
-
-  // Swipe up on the shelf to show the hotseat.
-  SwipeUpOnShelf();
-  EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state());
-
-  ShelfViewTestAPI shelf_view_test_api(
-      GetPrimaryShelf()->shelf_widget()->shelf_view_for_testing());
-  ShelfAppButton* app_icon = shelf_view_test_api.GetButton(0);
-
-  // Accelerate the generation of the long press event.
-  ui::GestureConfiguration::GetInstance()->set_show_press_delay_in_ms(1);
-  ui::GestureConfiguration::GetInstance()->set_long_press_time_in_ms(1);
-
-  // Press the icon enough long time to generate the long press event.
-  GetEventGenerator()->MoveTouch(app_icon->GetBoundsInScreen().CenterPoint());
-  GetEventGenerator()->PressTouch();
-  ui::GestureConfiguration* gesture_config =
-      ui::GestureConfiguration::GetInstance();
-  const int long_press_delay_ms = gesture_config->long_press_time_in_ms() +
-                                  gesture_config->show_press_delay_in_ms();
-  base::RunLoop run_loop;
-  base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
-      FROM_HERE, run_loop.QuitClosure(),
-      base::TimeDelta::FromMilliseconds(long_press_delay_ms));
-  run_loop.Run();
-  GetEventGenerator()->ReleaseTouch();
-
-  // Expects that the hotseat's state is kExntended.
-  EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state());
-
-  // Ensures that the ink drop state is InkDropState::ACTIVATED before closing
-  // the menu.
-  app_icon->FireRippleActivationTimerForTest();
-}
-
 // Tests that swiping up on the hotseat does nothing.
 TEST_P(HotseatShelfLayoutManagerTest, SwipeUpOnHotseatBackgroundDoesNothing) {
   GetPrimaryShelf()->SetAutoHideBehavior(GetParam());
@@ -5563,6 +5454,46 @@
   EXPECT_FALSE(IsWindowDragInProgress());
   EXPECT_TRUE(window->transform().IsIdentity());
   EndScroll(/*is_fling=*/false, 0.f);
+
+  EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state());
+}
+
+// Test that gesture that starts within hotseat bounds, goes down to shelf, and
+// start moving up does not start window drag (as upward swipe from hotseat does
+// not start window drag either).
+TEST_F(ShelfLayoutManagerWindowDraggingTest,
+       NoOpIfDragSTartsAboveShelfAndMovesToShelf) {
+  std::unique_ptr<aura::Window> window =
+      AshTestBase::CreateTestWindow(gfx::Rect(0, 0, 400, 400));
+  wm::ActivateWindow(window.get());
+
+  Shelf* shelf = GetPrimaryShelf();
+  shelf->SetAutoHideBehavior(ShelfAutoHideBehavior::kAlways);
+  SwipeUpOnShelf();
+  EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
+  EXPECT_EQ(HotseatState::kExtended, GetShelfLayoutManager()->hotseat_state());
+
+  gfx::Rect hotseat_bounds =
+      GetShelfWidget()->hotseat_widget()->GetWindowBoundsInScreen();
+  StartScroll(hotseat_bounds.CenterPoint());
+  EXPECT_FALSE(IsWindowDragInProgress());
+  EXPECT_TRUE(window->transform().IsIdentity());
+
+  const gfx::Vector2d vector_from_hotseat_to_shelf_center =
+      hotseat_bounds.CenterPoint() -
+      GetShelfWidget()->GetWindowBoundsInScreen().CenterPoint();
+  UpdateScroll(vector_from_hotseat_to_shelf_center.y());
+
+  EXPECT_FALSE(IsWindowDragInProgress());
+  EXPECT_TRUE(window->transform().IsIdentity());
+
+  UpdateScroll(-vector_from_hotseat_to_shelf_center.y());
+  EXPECT_FALSE(IsWindowDragInProgress());
+  EXPECT_TRUE(window->transform().IsIdentity());
+
+  EndScroll(/*is_fling=*/false, 0.f);
+  EXPECT_FALSE(IsWindowDragInProgress());
+  EXPECT_TRUE(window->transform().IsIdentity());
 }
 
 // Tests that the MRU window can only be dragged window after the hotseat is
diff --git a/ash/system/unified/unified_system_tray_bubble.cc b/ash/system/unified/unified_system_tray_bubble.cc
index 8e3f42d..630c02f 100644
--- a/ash/system/unified/unified_system_tray_bubble.cc
+++ b/ash/system/unified/unified_system_tray_bubble.cc
@@ -319,19 +319,21 @@
     return;
   }
 
-  // Don't close the bubble if the message center is gaining or losing
-  // activation.
+  // Don't close the bubble if the message center is gaining activation.
   if (features::IsUnifiedMessageCenterRefactorEnabled() &&
       tray_->IsMessageCenterBubbleShown()) {
     views::Widget* message_center_widget =
         tray_->message_center_bubble()->GetBubbleWidget();
     if (message_center_widget ==
-            views::Widget::GetWidgetForNativeView(gained_active) ||
-        (lost_active &&
-         message_center_widget ==
-             views::Widget::GetWidgetForNativeView(lost_active))) {
+        views::Widget::GetWidgetForNativeView(gained_active)) {
       return;
     }
+
+    // If the message center is not visible, ignore activation changes.
+    // Otherwise, this may cause a crash when closing the dialog via
+    // accelerator. See crbug.com/1041174.
+    if (!message_center_widget->IsVisible())
+      return;
   }
 
   tray_->CloseBubble();
diff --git a/base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java b/base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java
index b8d77d3b..9a40c14 100644
--- a/base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java
+++ b/base/android/java/src/org/chromium/base/process_launcher/ChildConnectionAllocator.java
@@ -33,6 +33,8 @@
  */
 public abstract class ChildConnectionAllocator {
     private static final String TAG = "ChildConnAllocator";
+    private static final String ZYGOTE_SUFFIX = "0";
+    private static final String NON_ZYGOTE_SUFFIX = "1";
 
     /** Factory interface. Used by tests to specialize created connections. */
     @VisibleForTesting
@@ -72,7 +74,7 @@
     /* package */ final String mServiceClassName;
     /* package */ final boolean mBindToCaller;
     /* package */ final boolean mBindAsExternalService;
-    private final boolean mUseStrongBinding;
+    /* package */ final boolean mUseStrongBinding;
 
     /* package */ ConnectionFactory mConnectionFactory = new ConnectionFactoryImpl();
 
@@ -125,9 +127,19 @@
             String serviceClassName, boolean bindToCaller, boolean bindAsExternalService,
             boolean useStrongBinding) {
         checkServiceExists(context, packageName, serviceClassName);
+        if (Build.VERSION.SDK_INT == 29) {
+            UserManager userManager =
+                    (UserManager) ContextUtils.getApplicationContext().getSystemService(
+                            Context.USER_SERVICE);
+            if (!ApiHelperForM.isSystemUser(userManager)) {
+                return new Android10WorkaroundAllocatorImpl(launcherHandler, freeSlotCallback,
+                        packageName, serviceClassName, bindToCaller, bindAsExternalService,
+                        useStrongBinding, MAX_VARIABLE_ALLOCATED);
+            }
+        }
         return new VariableSizeAllocatorImpl(launcherHandler, freeSlotCallback, packageName,
-                serviceClassName, bindToCaller, bindAsExternalService, useStrongBinding,
-                MAX_VARIABLE_ALLOCATED);
+                serviceClassName + ZYGOTE_SUFFIX, bindToCaller, bindAsExternalService,
+                useStrongBinding, MAX_VARIABLE_ALLOCATED);
     }
 
     /**
@@ -149,7 +161,17 @@
             boolean bindToCaller, boolean bindAsExternalService, boolean useStrongBinding,
             int maxAllocated) {
         return new VariableSizeAllocatorImpl(launcherHandler, freeSlotCallback, packageName,
-                serviceClassName + "0", bindToCaller, bindAsExternalService, useStrongBinding,
+                serviceClassName + ZYGOTE_SUFFIX, bindToCaller, bindAsExternalService,
+                useStrongBinding, maxAllocated);
+    }
+
+    @VisibleForTesting
+    public static Android10WorkaroundAllocatorImpl createWorkaroundForTesting(
+            Handler launcherHandler, String packageName, Runnable freeSlotCallback,
+            String serviceClassName, boolean bindToCaller, boolean bindAsExternalService,
+            boolean useStrongBinding, int maxAllocated) {
+        return new Android10WorkaroundAllocatorImpl(launcherHandler, freeSlotCallback, packageName,
+                serviceClassName, bindToCaller, bindAsExternalService, useStrongBinding,
                 maxAllocated);
     }
 
@@ -171,9 +193,6 @@
             final ChildProcessConnection.ServiceCallback serviceCallback) {
         assert isRunningOnLauncherThread();
 
-        ChildProcessConnection connection = doAllocate(context, serviceBundle);
-        if (connection == null) return null;
-
         // Wrap the service callbacks so that:
         // - we can intercept onChildProcessDied and clean-up connections
         // - the callbacks are actually posted so that this method will return before the callbacks
@@ -238,8 +257,7 @@
                     }
                 };
 
-        connection.start(mUseStrongBinding, serviceCallbackWrapper);
-        return connection;
+        return doAllocate(context, serviceBundle, serviceCallbackWrapper);
     }
 
     /** Free connection allocated by this allocator. */
@@ -280,7 +298,8 @@
         return mLauncherHandler.getLooper() == Looper.myLooper();
     }
 
-    /* package */ abstract ChildProcessConnection doAllocate(Context context, Bundle serviceBundle);
+    /* package */ abstract ChildProcessConnection doAllocate(Context context, Bundle serviceBundle,
+            ChildProcessConnection.ServiceCallback serviceCallback);
     /* package */ abstract void doFree(ChildProcessConnection connection);
 
     /** Implementation class accessed directly by tests. */
@@ -307,7 +326,8 @@
         }
 
         @Override
-        /* package */ ChildProcessConnection doAllocate(Context context, Bundle serviceBundle) {
+        /* package */ ChildProcessConnection doAllocate(Context context, Bundle serviceBundle,
+                ChildProcessConnection.ServiceCallback serviceCallback) {
             if (mFreeConnectionIndices.isEmpty()) {
                 Log.d(TAG, "Ran out of services to allocate.");
                 return null;
@@ -322,6 +342,7 @@
             mChildProcessConnections[slot] = connection;
             Log.d(TAG, "Allocator allocated and bound a connection, name: %s, slot: %d",
                     mServiceClassName, slot);
+            connection.start(mUseStrongBinding, serviceCallback);
             return connection;
         }
 
@@ -374,34 +395,37 @@
         private final ArraySet<ChildProcessConnection> mAllocatedConnections = new ArraySet<>();
         private int mNextInstance;
 
-        private static String getServiceSuffix() {
-            // Android Q has a bug in its app zygote implementation under secondary user (eg in a
-            // work profile). See crbug.com/1035432 for details. Disable using the app zygote in
-            // that case by using a non '0' suffix which is the only service entry that enables
-            // app zygote.
-            if (Build.VERSION.SDK_INT == 29) {
-                UserManager userManager =
-                        (UserManager) ContextUtils.getApplicationContext().getSystemService(
-                                Context.USER_SERVICE);
-                if (!ApiHelperForM.isSystemUser(userManager)) {
-                    return "1";
-                }
-            }
-            return "0";
-        }
-
+        // Note |serviceClassName| includes the service suffix.
         private VariableSizeAllocatorImpl(Handler launcherHandler, Runnable freeSlotCallback,
                 String packageName, String serviceClassName, boolean bindToCaller,
                 boolean bindAsExternalService, boolean useStrongBinding, int maxAllocated) {
-            super(launcherHandler, freeSlotCallback, packageName,
-                    serviceClassName + getServiceSuffix(), bindToCaller, bindAsExternalService,
-                    useStrongBinding);
+            super(launcherHandler, freeSlotCallback, packageName, serviceClassName, bindToCaller,
+                    bindAsExternalService, useStrongBinding);
             assert maxAllocated > 0;
             mMaxAllocated = maxAllocated;
         }
 
         @Override
-        /* package */ ChildProcessConnection doAllocate(Context context, Bundle serviceBundle) {
+        /* package */ ChildProcessConnection doAllocate(Context context, Bundle serviceBundle,
+                ChildProcessConnection.ServiceCallback serviceCallback) {
+            ChildProcessConnection connection = allocate(context, serviceBundle);
+            if (connection == null) return null;
+            mAllocatedConnections.add(connection);
+            connection.start(mUseStrongBinding, serviceCallback);
+            return connection;
+        }
+
+        /* package */ ChildProcessConnection tryAllocate(Context context, Bundle serviceBundle,
+                ChildProcessConnection.ServiceCallback serviceCallback) {
+            ChildProcessConnection connection = allocate(context, serviceBundle);
+            if (connection == null) return null;
+            boolean startResult = connection.tryStart(mUseStrongBinding, serviceCallback);
+            if (!startResult) return null;
+            mAllocatedConnections.add(connection);
+            return connection;
+        }
+
+        private ChildProcessConnection allocate(Context context, Bundle serviceBundle) {
             if (mAllocatedConnections.size() >= mMaxAllocated) {
                 Log.d(TAG, "Ran out of UIDs to allocate.");
                 return null;
@@ -413,13 +437,17 @@
                     mConnectionFactory.createConnection(context, serviceName, mBindToCaller,
                             mBindAsExternalService, serviceBundle, instanceName);
             assert connection != null;
-            mAllocatedConnections.add(connection);
             return connection;
         }
 
         @Override
         /* package */ void doFree(ChildProcessConnection connection) {
-            mAllocatedConnections.remove(connection);
+            boolean result = mAllocatedConnections.remove(connection);
+            assert result;
+        }
+
+        /* package */ boolean wasConnectionAllocated(ChildProcessConnection connection) {
+            return mAllocatedConnections.contains(connection);
         }
 
         @Override
@@ -437,4 +465,76 @@
             return mAllocatedConnections.size() > 0;
         }
     }
+
+    /**
+     * Workaround allocator for Android 10 bug.
+     * Android 10 has a bug that UID used for non-primary user cannot be freed correctly,
+     * eventually exhausting the pool of UIDs for isolated services. There is a global pool of
+     * 1000 UIDs, and each app zygote has a smaller pool of 100; the bug appplies to both cases.
+     * The leaked UID in the app zygote pool are released when the zygote is killed; leaked UIDs in
+     * the global pool are released when the device is rebooted. So way to slightly delay until the
+     * device needs to be rebooted is to use up the app zygote pool first before using the
+     * non-zygote global pool.
+     */
+    private static class Android10WorkaroundAllocatorImpl extends ChildConnectionAllocator {
+        private final VariableSizeAllocatorImpl mZygoteAllocator;
+        private final VariableSizeAllocatorImpl mNonZygoteAllocator;
+
+        private Android10WorkaroundAllocatorImpl(Handler launcherHandler, Runnable freeSlotCallback,
+                String packageName, String serviceClassName, boolean bindToCaller,
+                boolean bindAsExternalService, boolean useStrongBinding, int maxAllocated) {
+            super(launcherHandler, freeSlotCallback, packageName, serviceClassName, bindToCaller,
+                    bindAsExternalService, useStrongBinding);
+            mZygoteAllocator = new VariableSizeAllocatorImpl(launcherHandler, freeSlotCallback,
+                    packageName, serviceClassName + ZYGOTE_SUFFIX, bindToCaller,
+                    bindAsExternalService, useStrongBinding, maxAllocated);
+            mNonZygoteAllocator = new VariableSizeAllocatorImpl(launcherHandler, freeSlotCallback,
+                    packageName, serviceClassName + NON_ZYGOTE_SUFFIX, bindToCaller,
+                    bindAsExternalService, useStrongBinding, maxAllocated);
+        }
+
+        @Override
+        /* package */ ChildProcessConnection doAllocate(Context context, Bundle serviceBundle,
+                ChildProcessConnection.ServiceCallback serviceCallback) {
+            ChildProcessConnection connection =
+                    mZygoteAllocator.tryAllocate(context, serviceBundle, serviceCallback);
+            if (connection != null) return connection;
+            return mNonZygoteAllocator.doAllocate(context, serviceBundle, serviceCallback);
+        }
+
+        @Override
+        /* package */ void doFree(ChildProcessConnection connection) {
+            if (mZygoteAllocator.wasConnectionAllocated(connection)) {
+                mZygoteAllocator.doFree(connection);
+            } else if (mNonZygoteAllocator.wasConnectionAllocated(connection)) {
+                mNonZygoteAllocator.doFree(connection);
+            } else {
+                assert false;
+            }
+        }
+
+        @Override
+        public int getNumberOfServices() {
+            return -1;
+        }
+
+        @Override
+        public int allocatedConnectionsCountForTesting() {
+            return mZygoteAllocator.allocatedConnectionsCountForTesting()
+                    + mNonZygoteAllocator.allocatedConnectionsCountForTesting();
+        }
+
+        @Override
+        public boolean anyConnectionAllocated() {
+            return mZygoteAllocator.anyConnectionAllocated()
+                    || mNonZygoteAllocator.anyConnectionAllocated();
+        }
+
+        @Override
+        public void setConnectionFactoryForTesting(ConnectionFactory connectionFactory) {
+            super.setConnectionFactoryForTesting(connectionFactory);
+            mZygoteAllocator.setConnectionFactoryForTesting(connectionFactory);
+            mNonZygoteAllocator.setConnectionFactoryForTesting(connectionFactory);
+        }
+    }
 }
diff --git a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java
index dcf824b8..c688e9c 100644
--- a/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java
+++ b/base/android/java/src/org/chromium/base/process_launcher/ChildProcessConnection.java
@@ -416,6 +416,27 @@
         }
     }
 
+    // This is the same as start, but returns a boolean whether bind succeeded. Also on failure,
+    // no method is called on |serviceCallback| so the allocation can be tried again. This is
+    // package private and is meant to be used by Android10WorkaroundAllocatorImpl. See comment
+    // there for details.
+    boolean tryStart(boolean useStrongBinding, ServiceCallback serviceCallback) {
+        try {
+            TraceEvent.begin("ChildProcessConnection.tryStart");
+            assert isRunningOnLauncherThread();
+            assert mConnectionParams
+                    == null : "setupConnection() called before start() in ChildProcessConnection.";
+
+            if (!bind(useStrongBinding)) {
+                return false;
+            }
+            mServiceCallback = serviceCallback;
+        } finally {
+            TraceEvent.end("ChildProcessConnection.tryStart");
+        }
+        return true;
+    }
+
     /**
      * Call bindService again on this connection. This must be called while connection is already
      * bound. This is useful for controlling the recency of this connection, and also for updating
diff --git a/base/android/junit/src/org/chromium/base/process_launcher/ChildConnectionAllocatorTest.java b/base/android/junit/src/org/chromium/base/process_launcher/ChildConnectionAllocatorTest.java
index 599fd0e..e5fd740 100644
--- a/base/android/junit/src/org/chromium/base/process_launcher/ChildConnectionAllocatorTest.java
+++ b/base/android/junit/src/org/chromium/base/process_launcher/ChildConnectionAllocatorTest.java
@@ -138,6 +138,7 @@
 
     private ChildConnectionAllocator.FixedSizeAllocatorImpl mAllocator;
     private ChildConnectionAllocator mVariableSizeAllocator;
+    private ChildConnectionAllocator mWorkaroundAllocator;
 
     @Before
     public void setUp() {
@@ -153,6 +154,12 @@
                 true /* bindTocall */, false /* bindAsExternalService */,
                 false /* useStrongBinding */, 10);
         mVariableSizeAllocator.setConnectionFactoryForTesting(mTestConnectionFactory);
+
+        mWorkaroundAllocator = ChildConnectionAllocator.createWorkaroundForTesting(new Handler(),
+                TEST_PACKAGE_NAME, null /* freeSlotCallback */, "AllocatorTest",
+                true /* bindTocall */, false /* bindAsExternalService */,
+                false /* useStrongBinding */, 10);
+        mWorkaroundAllocator.setConnectionFactoryForTesting(mTestConnectionFactory);
     }
 
     @Test
@@ -211,6 +218,16 @@
         doTestQueueAllocation(mVariableSizeAllocator, freeConnectionCallback);
     }
 
+    @Test
+    @Feature({"ProcessManagement"})
+    public void testQueueAllocationWorkaround() {
+        Runnable freeConnectionCallback = mock(Runnable.class);
+        mWorkaroundAllocator = ChildConnectionAllocator.createWorkaroundForTesting(new Handler(),
+                TEST_PACKAGE_NAME, freeConnectionCallback, "AllocatorTest", true /* bindToCaller */,
+                false /* bindAsExternalService */, false /* useStrongBinding */, 1);
+        doTestQueueAllocation(mWorkaroundAllocator, freeConnectionCallback);
+    }
+
     private void doTestQueueAllocation(
             ChildConnectionAllocator allocator, Runnable freeConnectionCallback) {
         allocator.setConnectionFactoryForTesting(mTestConnectionFactory);
@@ -303,6 +320,13 @@
 
     @Test
     @Feature({"ProcessManagement"})
+    public void testOnChildStartedCallbackWorkaround() {
+        runTestWithConnectionCallbacks(mWorkaroundAllocator, true /* onChildStarted */,
+                false /* onChildStartFailed */, false /* onChildProcessDied */);
+    }
+
+    @Test
+    @Feature({"ProcessManagement"})
     public void testOnChildStartFailedCallback() {
         runTestWithConnectionCallbacks(mAllocator, false /* onChildStarted */,
                 true /* onChildStartFailed */, false /* onChildProcessDied */);
@@ -317,6 +341,13 @@
 
     @Test
     @Feature({"ProcessManagement"})
+    public void testOnChildStartFailedCallbackWorkaround() {
+        runTestWithConnectionCallbacks(mWorkaroundAllocator, false /* onChildStarted */,
+                true /* onChildStartFailed */, false /* onChildProcessDied */);
+    }
+
+    @Test
+    @Feature({"ProcessManagement"})
     public void testOnChildProcessDiedCallback() {
         runTestWithConnectionCallbacks(mAllocator, false /* onChildStarted */,
                 false /* onChildStartFailed */, true /* onChildProcessDied */);
@@ -329,6 +360,13 @@
                 false /* onChildStartFailed */, true /* onChildProcessDied */);
     }
 
+    @Test
+    @Feature({"ProcessManagement"})
+    public void testOnChildProcessDiedCallbackWorkaround() {
+        runTestWithConnectionCallbacks(mWorkaroundAllocator, false /* onChildStarted */,
+                false /* onChildStartFailed */, true /* onChildProcessDied */);
+    }
+
     /**
      * Tests that the allocator clears the connection when it fails to bind/process dies.
      */
@@ -391,6 +429,12 @@
 
     @Test
     @Feature({"ProcessManagement"})
+    public void testFreeConnectionOnChildStartFailedWorkaround() {
+        testFreeConnection(mWorkaroundAllocator, FREE_CONNECTION_TEST_CALLBACK_START_FAILED);
+    }
+
+    @Test
+    @Feature({"ProcessManagement"})
     public void testFreeConnectionOnChildProcessDied() {
         testFreeConnection(mAllocator, FREE_CONNECTION_TEST_CALLBACK_PROCESS_DIED);
     }
@@ -400,4 +444,10 @@
     public void testFreeConnectionOnChildProcessDiedVariableSize() {
         testFreeConnection(mVariableSizeAllocator, FREE_CONNECTION_TEST_CALLBACK_PROCESS_DIED);
     }
+
+    @Test
+    @Feature({"ProcessManagement"})
+    public void testFreeConnectionOnChildProcessDiedWorkaround() {
+        testFreeConnection(mWorkaroundAllocator, FREE_CONNECTION_TEST_CALLBACK_PROCESS_DIED);
+    }
 }
diff --git a/build/android/pylib/device/commands/java/src/org/chromium/android/commands/unzip/Unzip.java b/build/android/pylib/device/commands/java/src/org/chromium/android/commands/unzip/Unzip.java
index 419c3a0..cf0ff67 100644
--- a/build/android/pylib/device/commands/java/src/org/chromium/android/commands/unzip/Unzip.java
+++ b/build/android/pylib/device/commands/java/src/org/chromium/android/commands/unzip/Unzip.java
@@ -4,8 +4,6 @@
 
 package org.chromium.android.commands.unzip;
 
-import org.chromium.base.Log;
-
 import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 import java.io.File;
@@ -28,8 +26,7 @@
         try {
             (new Unzip()).run(args);
         } catch (RuntimeException e) {
-            Log.e(TAG, "unzip failed", e);
-            System.err.println(e.toString());
+            e.printStackTrace();
             System.exit(1);
         }
     }
diff --git a/build/android/pylib/local/emulator/ini.py b/build/android/pylib/local/emulator/ini.py
index eaa17e4..8b8f0e8 100644
--- a/build/android/pylib/local/emulator/ini.py
+++ b/build/android/pylib/local/emulator/ini.py
@@ -9,6 +9,8 @@
   ret = {}
   for line in ini_str.splitlines():
     key, val = line.split('=', 1)
+    key = key.strip()
+    val = val.strip()
     if strict and key in ret:
       raise ValueError('Multiple entries present for key "%s"' % key)
     ret[key] = val
@@ -22,8 +24,8 @@
 
 def dumps(obj):
   ret = ''
-  for k, v in obj.iteritems():
-    ret += '%s=%s\n' % (k, str(v))
+  for k, v in sorted(obj.iteritems()):
+    ret += '%s = %s\n' % (k, str(v))
   return ret
 
 
diff --git a/build/android/pylib/local/emulator/ini_test.py b/build/android/pylib/local/emulator/ini_test.py
new file mode 100755
index 0000000..4bc9ddb
--- /dev/null
+++ b/build/android/pylib/local/emulator/ini_test.py
@@ -0,0 +1,68 @@
+#! /usr/bin/env python
+# 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.
+"""Tests for ini.py."""
+
+import textwrap
+import unittest
+
+from pylib.local.emulator import ini
+
+
+class IniTest(unittest.TestCase):
+  def testLoadsBasic(self):
+    ini_str = textwrap.dedent("""\
+        foo.bar = 1
+        foo.baz= example
+        bar.bad =/path/to/thing
+        """)
+    expected = {
+        'foo.bar': '1',
+        'foo.baz': 'example',
+        'bar.bad': '/path/to/thing',
+    }
+    self.assertEqual(expected, ini.loads(ini_str))
+
+  def testLoadsStrictFailure(self):
+    ini_str = textwrap.dedent("""\
+        foo.bar = 1
+        foo.baz = example
+        bar.bad = /path/to/thing
+        foo.bar = duplicate
+        """)
+    with self.assertRaises(ValueError):
+      ini.loads(ini_str, strict=True)
+
+  def testLoadsPermissive(self):
+    ini_str = textwrap.dedent("""\
+        foo.bar = 1
+        foo.baz = example
+        bar.bad = /path/to/thing
+        foo.bar = duplicate
+        """)
+    expected = {
+        'foo.bar': 'duplicate',
+        'foo.baz': 'example',
+        'bar.bad': '/path/to/thing',
+    }
+    self.assertEqual(expected, ini.loads(ini_str, strict=False))
+
+  def testDumpsBasic(self):
+    ini_contents = {
+        'foo.bar': '1',
+        'foo.baz': 'example',
+        'bar.bad': '/path/to/thing',
+    }
+    # ini.dumps is expected to dump to string alphabetically
+    # by key.
+    expected = textwrap.dedent("""\
+        bar.bad = /path/to/thing
+        foo.bar = 1
+        foo.baz = example
+        """)
+    self.assertEqual(expected, ini.dumps(ini_contents))
+
+
+if __name__ == '__main__':
+  unittest.main()
diff --git a/build/config/c++/c++.gni b/build/config/c++/c++.gni
index 754bb914..5ced459 100644
--- a/build/config/c++/c++.gni
+++ b/build/config/c++/c++.gni
@@ -12,7 +12,9 @@
   # is not supported.
   use_custom_libcxx =
       is_fuchsia || is_android || is_mac || (is_ios && !use_xcode_clang) ||
-      (is_win && is_clang) || is_linux
+      (is_win && is_clang) ||
+      (is_linux &&
+       (!is_chromeos || default_toolchain != "//build/toolchain/cros:target"))
 
   # Use libc++ instead of stdlibc++ when using the host_cpu toolchain, even if
   # use_custom_libcxx is false. This is useful for cross-compiles where a custom
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py
index 9db0ea45..18758e2 100755
--- a/build/vs_toolchain.py
+++ b/build/vs_toolchain.py
@@ -140,7 +140,7 @@
 def GetVisualStudioVersion():
   """Return best available version of Visual Studio.
   """
-  supported_versions = MSVS_VERSIONS.keys()
+  supported_versions = list(MSVS_VERSIONS.keys())
 
   # VS installed in depot_tools for Googlers
   if bool(int(os.environ.get('DEPOT_TOOLS_WIN_TOOLCHAIN', '1'))):
diff --git a/cc/metrics/frame_sequence_tracker.cc b/cc/metrics/frame_sequence_tracker.cc
index 8b2f09c..1cd55fe 100644
--- a/cc/metrics/frame_sequence_tracker.cc
+++ b/cc/metrics/frame_sequence_tracker.cc
@@ -466,13 +466,11 @@
   DCHECK(!is_inside_frame_) << TRACKER_DCHECK_MSG;
   is_inside_frame_ = true;
 
-  DCHECK_EQ(last_started_impl_sequence_, 0u) << TRACKER_DCHECK_MSG;
-  DCHECK_EQ(last_processed_impl_sequence_, 0u) << TRACKER_DCHECK_MSG;
-
   if (args.type == viz::BeginFrameArgs::NORMAL)
     impl_frames_.insert(args.frame_id);
 #endif
 
+  DCHECK_EQ(last_started_impl_sequence_, 0u) << TRACKER_DCHECK_MSG;
   last_started_impl_sequence_ = args.frame_id.sequence_number;
   if (reset_all_state_) {
     begin_impl_frame_data_ = {};
@@ -506,19 +504,24 @@
   TRACKER_TRACE_STREAM << "B(" << begin_main_frame_data_.previous_sequence
                        << "," << args.frame_id.sequence_number << ")";
 
-  if (ShouldIgnoreSequence(args.frame_id.sequence_number))
+  if (first_received_main_sequence_ &&
+      first_received_main_sequence_ > args.frame_id.sequence_number) {
     return;
+  }
+
+  if (!first_received_main_sequence_ &&
+      ShouldIgnoreSequence(args.frame_id.sequence_number)) {
+    return;
+  }
 
 #if DCHECK_IS_ON()
   if (args.type == viz::BeginFrameArgs::NORMAL) {
-    DCHECK(impl_frames_.contains(args.frame_id));
+    DCHECK(impl_frames_.contains(args.frame_id)) << TRACKER_DCHECK_MSG;
   }
 #endif
 
-  // TODO(sad, xidachen): This DCHECK needs to be turned on, but the synthesized
-  // BeginMainFrame notifications from LayerTreeHostImpl needs to be removed
-  // first.
-  // DCHECK_EQ(awaiting_main_response_sequence_, 0u) << TRACKER_DCHECK_MSG;
+  DCHECK_EQ(awaiting_main_response_sequence_, 0u) << TRACKER_DCHECK_MSG;
+  last_processed_main_sequence_latency_ = 0;
   awaiting_main_response_sequence_ = args.frame_id.sequence_number;
 
   UpdateTrackedFrameData(&begin_main_frame_data_, args.frame_id.source_id,
@@ -542,11 +545,15 @@
   TRACKER_TRACE_STREAM << "E(" << args.frame_id.sequence_number << ")";
   if (first_received_main_sequence_ &&
       args.frame_id.sequence_number >= first_received_main_sequence_) {
-    // TODO(sad, xidachen): This DCHECK needs to be turned on, but the
-    // synthesized BeginMainFrame notifications from LayerTreeHostImpl needs to
-    // be removed first.
-    // DCHECK_EQ(awaiting_main_response_sequence_,
-    //           args.frame_id.sequence_number) << TRACKER_DCHECK_MSG;
+    if (awaiting_main_response_sequence_) {
+      DCHECK_EQ(awaiting_main_response_sequence_, args.frame_id.sequence_number)
+          << TRACKER_DCHECK_MSG;
+    }
+    DCHECK_EQ(last_processed_main_sequence_latency_, 0u) << TRACKER_DCHECK_MSG;
+    last_processed_main_sequence_ = args.frame_id.sequence_number;
+    last_processed_main_sequence_latency_ =
+        std::max(last_started_impl_sequence_, last_processed_impl_sequence_) -
+        args.frame_id.sequence_number;
     awaiting_main_response_sequence_ = 0;
   }
 }
@@ -591,6 +598,7 @@
   if (!ShouldIgnoreBeginFrameSource(origin_args.frame_id.source_id) &&
       main_changes_after_sequence_started && main_changes_include_new_changes &&
       !main_change_had_no_damage) {
+    submitted_frame_had_new_main_content_ = true;
     TRACKER_TRACE_STREAM << "S(" << origin_args.frame_id.sequence_number << ")";
 
     last_submitted_main_sequence_ = origin_args.frame_id.sequence_number;
@@ -628,6 +636,13 @@
     return;
   }
 
+  if (compositor_frame_submitted_ && submitted_frame_had_new_main_content_ &&
+      last_processed_main_sequence_latency_) {
+    // If a compositor frame was submitted with new content from the
+    // main-thread, then make sure the latency gets accounted for.
+    main_throughput().frames_expected += last_processed_main_sequence_latency_;
+  }
+
   // It is possible that the compositor claims there was no damage from the
   // compositor, but before the frame ends, it submits a compositor frame (e.g.
   // with some damage from main). In such cases, the compositor is still
@@ -649,15 +664,17 @@
   }
   frame_had_no_compositor_damage_ = false;
   compositor_frame_submitted_ = false;
+  submitted_frame_had_new_main_content_ = false;
+  last_processed_main_sequence_latency_ = 0;
 
 #if DCHECK_IS_ON()
   DCHECK(is_inside_frame_) << TRACKER_DCHECK_MSG;
-  DCHECK_EQ(last_started_impl_sequence_, last_processed_impl_sequence_)
-      << TRACKER_DCHECK_MSG;
   is_inside_frame_ = false;
 #endif
 
-  last_started_impl_sequence_ = last_processed_impl_sequence_ = 0;
+  DCHECK_EQ(last_started_impl_sequence_, last_processed_impl_sequence_)
+      << TRACKER_DCHECK_MSG;
+  last_started_impl_sequence_ = 0;
 }
 
 void FrameSequenceTracker::ReportFramePresented(
@@ -791,11 +808,17 @@
   if (last_no_main_damage_sequence_ == args.frame_id.sequence_number)
     return;
 
-  // TODO(sad, xidachen): This DCHECK needs to be turned on, but the synthesized
-  // BeginMainFrame notifications from LayerTreeHostImpl needs to be removed
-  // first.
-  // DCHECK_EQ(awaiting_main_response_sequence_, args.frame_id.sequence_number)
-  //    << TRACKER_DCHECK_MSG;
+  // It is possible for |awaiting_main_response_sequence_| to be zero here if a
+  // commit had already happened before (e.g. B(x)E(x)N(x)). So check that case
+  // here.
+  // XXX: Add a DCHECK() at least to make sure that's what happened?
+  if (awaiting_main_response_sequence_) {
+    DCHECK_EQ(awaiting_main_response_sequence_, args.frame_id.sequence_number)
+        << TRACKER_DCHECK_MSG;
+  } else {
+    DCHECK_EQ(last_processed_main_sequence_, args.frame_id.sequence_number)
+        << TRACKER_DCHECK_MSG;
+  }
   awaiting_main_response_sequence_ = 0;
 
   DCHECK_GT(main_throughput().frames_expected, 0u) << TRACKER_DCHECK_MSG;
@@ -826,7 +849,7 @@
   if (frame_data->previous_sequence &&
       frame_data->previous_source == source_id) {
     uint32_t current_latency = sequence_number - frame_data->previous_sequence;
-    DCHECK_GT(current_latency, 0u);
+    DCHECK_GT(current_latency, 0u) << TRACKER_DCHECK_MSG;
     frame_data->previous_sequence_delta = current_latency;
   } else {
     frame_data->previous_sequence_delta = 1;
diff --git a/cc/metrics/frame_sequence_tracker.h b/cc/metrics/frame_sequence_tracker.h
index 3bb4df2c..0b53f1b 100644
--- a/cc/metrics/frame_sequence_tracker.h
+++ b/cc/metrics/frame_sequence_tracker.h
@@ -399,6 +399,7 @@
 
   // Keeps track of whether a CompositorFrame is submitted during the frame.
   bool compositor_frame_submitted_ = false;
+  bool submitted_frame_had_new_main_content_ = false;
 
   // Keeps track of whether the frame-states should be reset.
   bool reset_all_state_ = false;
@@ -414,6 +415,9 @@
   uint64_t last_started_impl_sequence_ = 0;
   uint64_t last_processed_impl_sequence_ = 0;
 
+  uint64_t last_processed_main_sequence_ = 0;
+  uint64_t last_processed_main_sequence_latency_ = 0;
+
 #if DCHECK_IS_ON()
   bool is_inside_frame_ = false;
 
diff --git a/cc/metrics/frame_sequence_tracker_unittest.cc b/cc/metrics/frame_sequence_tracker_unittest.cc
index adc9645..1109e04 100644
--- a/cc/metrics/frame_sequence_tracker_unittest.cc
+++ b/cc/metrics/frame_sequence_tracker_unittest.cc
@@ -76,6 +76,8 @@
     if (damage_type & kImplDamage) {
       if (!(damage_type & kMainDamage)) {
         collection_.NotifyMainFrameCausedNoDamage(args);
+      } else {
+        collection_.NotifyMainFrameProcessed(args);
       }
       uint32_t frame_token = NextFrameToken();
       collection_.NotifySubmitFrame(frame_token, has_missing_content,
@@ -196,6 +198,7 @@
         case 'n':
         case 's':
         case 'e':
+        case 'E':
           ASSERT_EQ(*str, '(') << command;
           str = ParseNumber(++str, &sequence);
           ASSERT_EQ(*str, ')');
@@ -263,6 +266,11 @@
           collection_.NotifyFrameEnd(CreateBeginFrameArgs(source_id, sequence));
           break;
 
+        case 'E':
+          collection_.NotifyMainFrameProcessed(
+              CreateBeginFrameArgs(source_id, sequence));
+          break;
+
         case 'B':
           collection_.NotifyBeginMainFrame(
               CreateBeginFrameArgs(source_id, sequence));
@@ -563,14 +571,14 @@
 
   // Start and submit the next frame, with no damage from main.
   auto args = CreateBeginFrameArgs(source, ++sequence);
-  StartImplAndMainFrames(args);
+  collection_.NotifyBeginImplFrame(args);
   frame_token = NextFrameToken();
-  collection_.NotifyMainFrameCausedNoDamage(args);
   collection_.NotifySubmitFrame(frame_token, /*has_missing_content=*/false,
                                 viz::BeginFrameAck(args, true), first_args);
   collection_.NotifyFrameEnd(args);
 
   // Now, submit a frame with damage from main from |second_args|.
+  collection_.NotifyMainFrameProcessed(second_args);
   args = CreateBeginFrameArgs(source, ++sequence);
   StartImplAndMainFrames(args);
   frame_token = NextFrameToken();
@@ -604,6 +612,7 @@
   // frame).
   auto second_args = CreateBeginFrameArgs(source, ++sequence);
   collection_.NotifyBeginImplFrame(second_args);
+  collection_.NotifyMainFrameProcessed(first_args);
   collection_.NotifyBeginMainFrame(second_args);
   uint32_t frame_token = NextFrameToken();
   collection_.NotifySubmitFrame(frame_token, /*has_missing_content=*/false,
@@ -730,4 +739,23 @@
   EXPECT_EQ(ImplThroughput().frames_produced, 1u);
 }
 
+// b(2417)B(0,2417)E(2417)n(2417)N(2417,2417)
+
+TEST_F(FrameSequenceTrackerTest, SequenceNumberReset) {
+  const char sequence[] =
+      "b(6)B(0,6)n(6)e(6)Rb(1)B(0,1)N(1,1)n(1)e(1)b(2)B(1,2)n(2)e(2)";
+  GenerateSequence(sequence);
+  EXPECT_EQ(ImplThroughput().frames_expected, 0u);
+  EXPECT_EQ(MainThroughput().frames_expected, 1u);
+}
+
+TEST_F(FrameSequenceTrackerTest, MainThroughputWithHighLatency) {
+  const char sequence[] = "b(1)B(0,1)n(1)e(1)b(2)E(1)s(1)S(1)e(2)P(1)";
+  GenerateSequence(sequence);
+  EXPECT_EQ(ImplThroughput().frames_expected, 1u);
+  EXPECT_EQ(ImplThroughput().frames_produced, 1u);
+  EXPECT_EQ(MainThroughput().frames_expected, 2u);
+  EXPECT_EQ(MainThroughput().frames_produced, 1u);
+}
+
 }  // namespace cc
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
index 67453e2..40fc476 100644
--- a/cc/trees/layer_tree_host_impl.cc
+++ b/cc/trees/layer_tree_host_impl.cc
@@ -363,8 +363,7 @@
 }
 
 void LayerTreeHostImpl::DidSendBeginMainFrame(const viz::BeginFrameArgs& args) {
-  if (impl_thread_phase_ == ImplThreadPhase::INSIDE_IMPL_FRAME &&
-      !begin_main_frame_sent_during_impl_) {
+  if (!begin_main_frame_sent_during_impl_) {
     begin_main_frame_sent_during_impl_ = true;
     frame_trackers_.NotifyBeginMainFrame(args);
   }
@@ -2308,14 +2307,6 @@
   // outside of begin-impl frame pipeline. Avoid notifying the trackers in such
   // cases.
   if (impl_thread_phase_ == ImplThreadPhase::INSIDE_IMPL_FRAME) {
-    if (!begin_main_frame_sent_during_impl_) {
-      frame_trackers_.NotifyBeginMainFrame(
-          current_begin_frame_tracker_.Current());
-      if (!begin_main_frame_expected_during_impl_) {
-        frame_trackers_.NotifyMainFrameCausedNoDamage(
-            current_begin_frame_tracker_.Current());
-      }
-    }
     frame_trackers_.NotifySubmitFrame(
         compositor_frame.metadata.frame_token, frame->has_missing_content,
         frame->begin_frame_ack, frame->origin_begin_main_frame_args);
@@ -2681,12 +2672,7 @@
   frame_trackers_.NotifyBeginImplFrame(args);
 
   begin_main_frame_expected_during_impl_ = client_->IsBeginMainFrameExpected();
-  if (begin_main_frame_expected_during_impl_) {
-    begin_main_frame_sent_during_impl_ = true;
-    frame_trackers_.NotifyBeginMainFrame(args);
-  } else {
-    begin_main_frame_sent_during_impl_ = false;
-  }
+  begin_main_frame_sent_during_impl_ = false;
 
   if (is_likely_to_require_a_draw_) {
     // Optimistically schedule a draw. This will let us expect the tile manager
diff --git a/cc/trees/proxy_impl.cc b/cc/trees/proxy_impl.cc
index 636d567..b04b885 100644
--- a/cc/trees/proxy_impl.cc
+++ b/cc/trees/proxy_impl.cc
@@ -252,6 +252,7 @@
     CompletionEvent* completion,
     LayerTreeHost* layer_tree_host,
     base::TimeTicks main_thread_start_time,
+    const viz::BeginFrameArgs& commit_args,
     bool hold_commit_for_activation) {
   TRACE_EVENT0("cc", "ProxyImpl::NotifyReadyToCommitOnImpl");
   DCHECK(!commit_completion_event_);
@@ -270,8 +271,7 @@
   // But, we can avoid a PostTask in here.
   scheduler_->NotifyBeginMainFrameStarted(main_thread_start_time);
 
-  host_impl_->ReadyToCommit(
-      scheduler_->last_dispatched_begin_main_frame_args());
+  host_impl_->ReadyToCommit(commit_args);
 
   commit_completion_event_ =
       std::make_unique<ScopedCompletionEvent>(completion);
diff --git a/cc/trees/proxy_impl.h b/cc/trees/proxy_impl.h
index 89e4b18..5457428f 100644
--- a/cc/trees/proxy_impl.h
+++ b/cc/trees/proxy_impl.h
@@ -61,6 +61,7 @@
   void NotifyReadyToCommitOnImpl(CompletionEvent* completion,
                                  LayerTreeHost* layer_tree_host,
                                  base::TimeTicks main_thread_start_time,
+                                 const viz::BeginFrameArgs& commit_args,
                                  bool hold_commit_for_activation);
   void SetSourceURL(ukm::SourceId source_id, const GURL& url);
   void ClearHistory();
diff --git a/cc/trees/proxy_main.cc b/cc/trees/proxy_main.cc
index 16431892..b94a19c 100644
--- a/cc/trees/proxy_main.cc
+++ b/cc/trees/proxy_main.cc
@@ -340,6 +340,7 @@
         base::BindOnce(&ProxyImpl::NotifyReadyToCommitOnImpl,
                        base::Unretained(proxy_impl_.get()), &completion,
                        layer_tree_host_, begin_main_frame_start_time,
+                       begin_main_frame_state->begin_frame_args,
                        hold_commit_for_activation));
     completion.Wait();
   }
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 364c38d7..ba83db7 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -408,6 +408,7 @@
     "//chrome/browser:sharing_send_message_result_generated_enum",
     "//chrome/browser/notifications/scheduler/public:jni_enums",
     "//chrome/browser/supervised_user/supervised_user_error_page:enums_srcjar",
+    "//chrome/browser/ui:cookie_controls_controller_status_javagen",
     "//chrome/browser/ui:tab_model_enums_java",
     "//components/autofill_assistant/browser:autofill_assistant_enums_java",
     "//components/browsing_data/core:browsing_data_utils_java",
@@ -2769,6 +2770,7 @@
     "java/src/org/chromium/chrome/browser/settings/privacy/BrowsingDataBridge.java",
     "java/src/org/chromium/chrome/browser/settings/privacy/BrowsingDataCounterBridge.java",
     "java/src/org/chromium/chrome/browser/settings/privacy/PrivacyPreferencesManager.java",
+    "java/src/org/chromium/chrome/browser/settings/website/CookieControlsBridge.java",
     "java/src/org/chromium/chrome/browser/settings/website/WebsitePreferenceBridge.java",
     "java/src/org/chromium/chrome/browser/sharing/SharingJNIBridge.java",
     "java/src/org/chromium/chrome/browser/sharing/SharingServiceProxy.java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 2ddf877e..78166ca 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -1323,6 +1323,7 @@
   "java/src/org/chromium/chrome/browser/policy/PolicyAuditor.java",
   "java/src/org/chromium/chrome/browser/prerender/ChromePrerenderService.java",
   "java/src/org/chromium/chrome/browser/prerender/ExternalPrerenderHandler.java",
+  "java/src/org/chromium/chrome/browser/previews/Previews.java",
   "java/src/org/chromium/chrome/browser/previews/PreviewsAndroidBridge.java",
   "java/src/org/chromium/chrome/browser/previews/PreviewsUma.java",
   "java/src/org/chromium/chrome/browser/printing/PrintShareActivity.java",
@@ -1467,6 +1468,7 @@
   "java/src/org/chromium/chrome/browser/settings/website/ContentSetting.java",
   "java/src/org/chromium/chrome/browser/settings/website/ContentSettingException.java",
   "java/src/org/chromium/chrome/browser/settings/website/ContentSettingsResources.java",
+  "java/src/org/chromium/chrome/browser/settings/website/CookieControlsBridge.java",
   "java/src/org/chromium/chrome/browser/settings/website/LocalStorageInfo.java",
   "java/src/org/chromium/chrome/browser/settings/website/LocationCategory.java",
   "java/src/org/chromium/chrome/browser/settings/website/ManageSpaceActivity.java",
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index 0c2f94c..80c9772 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -420,6 +420,7 @@
   "javatests/src/org/chromium/chrome/browser/settings/privacy/PrivacyPreferencesManagerNativeTest.java",
   "javatests/src/org/chromium/chrome/browser/settings/search_engine/SearchEngineSettingsTest.java",
   "javatests/src/org/chromium/chrome/browser/settings/themes/ThemeSettingsFragmentTest.java",
+  "javatests/src/org/chromium/chrome/browser/settings/website/CookieControlsBridgeTest.java",
   "javatests/src/org/chromium/chrome/browser/settings/website/ManageSpaceActivityTest.java",
   "javatests/src/org/chromium/chrome/browser/settings/website/PermissionInfoTest.java",
   "javatests/src/org/chromium/chrome/browser/settings/website/SiteSettingsTest.java",
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParent.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParent.java
index be380a6..af5fc5c 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParent.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParent.java
@@ -19,12 +19,10 @@
 import android.support.v4.content.ContextCompat;
 import android.support.v4.graphics.drawable.DrawableCompat;
 import android.support.v4.widget.ImageViewCompat;
-import android.util.DisplayMetrics;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.WindowManager;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.PopupWindow;
@@ -41,6 +39,7 @@
 import org.chromium.chrome.browser.widget.ScrimView;
 import org.chromium.chrome.tab_ui.R;
 import org.chromium.components.browser_ui.widget.animation.Interpolators;
+import org.chromium.ui.display.DisplayAndroid;
 import org.chromium.ui.interpolators.BakedBezierInterpolator;
 
 import java.lang.annotation.Retention;
@@ -140,13 +139,10 @@
                 (int) context.getResources().getDimension(R.dimen.bottom_sheet_peek_height);
         mContainerParams = new FrameLayout.LayoutParams(
                 ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
-        DisplayMetrics displayMetrics = new DisplayMetrics();
-        ((WindowManager) context.getSystemService(Context.WINDOW_SERVICE))
-                .getDefaultDisplay()
-                .getMetrics(displayMetrics);
+        DisplayAndroid display = DisplayAndroid.getNonMultiDisplay(context);
         // Screen height and width when in portrait mode.
-        mScreenHeight = Math.max(displayMetrics.heightPixels, displayMetrics.widthPixels);
-        mScreenWidth = Math.min(displayMetrics.heightPixels, displayMetrics.widthPixels);
+        mScreenHeight = Math.max(display.getDisplayHeight(), display.getDisplayWidth());
+        mScreenWidth = Math.min(display.getDisplayHeight(), display.getDisplayWidth());
 
         mComponentCallbacks = new ComponentCallbacks() {
             @Override
@@ -837,4 +833,4 @@
     static void setSourceRectCallbackForTesting(Callback<RectF> callback) {
         sSourceRectCallbackForTesting = callback;
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphItemView.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphItemView.java
index 1ae39b75..1bacd62 100644
--- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphItemView.java
+++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphItemView.java
@@ -4,7 +4,6 @@
 
 package org.chromium.chrome.browser.tasks.tab_management;
 
-import android.app.Activity;
 import android.content.ComponentCallbacks;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -19,7 +18,6 @@
 import android.support.v4.view.ViewCompat;
 import android.support.v7.content.res.AppCompatResources;
 import android.util.AttributeSet;
-import android.util.DisplayMetrics;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -34,6 +32,7 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.browser.widget.ScrimView;
 import org.chromium.chrome.tab_ui.R;
+import org.chromium.ui.display.DisplayAndroid;
 import org.chromium.ui.widget.ChromeImageView;
 
 /**
@@ -193,9 +192,7 @@
     }
 
     private void updateMargins(int orientation) {
-        DisplayMetrics displayMetrics = new DisplayMetrics();
-        ((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
-        int screenHeight = displayMetrics.heightPixels;
+        int screenHeight = DisplayAndroid.getNonMultiDisplay(getContext()).getDisplayHeight();
 
         int dialogHeight =
                 (int) mContext.getResources().getDimension(R.dimen.tab_grid_iph_dialog_height);
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParentTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParentTest.java
index ce504ec1..1e09caf 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParentTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridDialogParentTest.java
@@ -53,25 +53,28 @@
         super.setUpTest();
         TabFeatureUtilities.setIsTabToGtsAnimationEnabledForTesting(true);
 
-        mDummyParent = new FrameLayout(getActivity());
-        mTabGridDialogParent = new TabGridDialogParent(getActivity(), mDummyParent);
-        mPopoupWindow = mTabGridDialogParent.getPopupWindowForTesting();
-        FrameLayout tabGridDialogParentView =
-                mTabGridDialogParent.getTabGridDialogParentViewForTesting();
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mDummyParent = new FrameLayout(getActivity());
+            mTabGridDialogParent = new TabGridDialogParent(getActivity(), mDummyParent);
+            mPopoupWindow = mTabGridDialogParent.getPopupWindowForTesting();
+            FrameLayout tabGridDialogParentView =
+                    mTabGridDialogParent.getTabGridDialogParentViewForTesting();
 
-        mTabGridDialogContainer = tabGridDialogParentView.findViewById(R.id.dialog_container_view);
-        mUngroupBar = mTabGridDialogContainer.findViewById(R.id.dialog_ungroup_bar);
-        mUngroupBarTextView = mUngroupBar.findViewById(R.id.dialog_ungroup_bar_text);
-        mContainerParams = (FrameLayout.LayoutParams) mTabGridDialogContainer.getLayoutParams();
-        mAnimationCardView = mTabGridDialogParent.getAnimationCardViewForTesting();
-        mBackgroundFrameView = tabGridDialogParentView.findViewById(R.id.dialog_frame);
+            mTabGridDialogContainer =
+                    tabGridDialogParentView.findViewById(R.id.dialog_container_view);
+            mUngroupBar = mTabGridDialogContainer.findViewById(R.id.dialog_ungroup_bar);
+            mUngroupBarTextView = mUngroupBar.findViewById(R.id.dialog_ungroup_bar_text);
+            mContainerParams = (FrameLayout.LayoutParams) mTabGridDialogContainer.getLayoutParams();
+            mAnimationCardView = mTabGridDialogParent.getAnimationCardViewForTesting();
+            mBackgroundFrameView = tabGridDialogParentView.findViewById(R.id.dialog_frame);
 
-        mToolbarHeight =
-                (int) getActivity().getResources().getDimension(R.dimen.tab_group_toolbar_height);
-        mTopMargin =
-                (int) getActivity().getResources().getDimension(R.dimen.tab_grid_dialog_top_margin);
-        mSideMargin = (int) getActivity().getResources().getDimension(
-                R.dimen.tab_grid_dialog_side_margin);
+            mToolbarHeight = (int) getActivity().getResources().getDimension(
+                    R.dimen.tab_group_toolbar_height);
+            mTopMargin = (int) getActivity().getResources().getDimension(
+                    R.dimen.tab_grid_dialog_top_margin);
+            mSideMargin = (int) getActivity().getResources().getDimension(
+                    R.dimen.tab_grid_dialog_side_margin);
+        });
     }
 
     @Test
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphItemTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphItemTest.java
index 0d8ce755..e74ba47 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphItemTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridIphItemTest.java
@@ -24,7 +24,6 @@
 import android.os.Build;
 import android.support.test.espresso.NoMatchingRootException;
 import android.support.test.filters.MediumTest;
-import android.util.DisplayMetrics;
 import android.view.ViewGroup;
 import android.widget.TextView;
 
@@ -50,6 +49,8 @@
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.util.browser.Features;
 import org.chromium.content_public.browser.test.util.CriteriaHelper;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
+import org.chromium.ui.display.DisplayAndroid;
 import org.chromium.ui.test.util.UiRestriction;
 
 /** End-to-end tests for TabGridIphItem component. */
@@ -210,9 +211,8 @@
 
     private void verifyDialogMargins(ChromeTabbedActivity cta, int orientation) {
         verifyIphDialogShowing(cta);
-        DisplayMetrics displayMetrics = new DisplayMetrics();
-        cta.getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
-        int screenHeight = displayMetrics.heightPixels;
+        int screenHeight = TestThreadUtils.runOnUiThreadBlockingNoException(
+                () -> DisplayAndroid.getNonMultiDisplay(cta).getDisplayHeight());
 
         int dialogHeight =
                 (int) cta.getResources().getDimension(R.dimen.tab_grid_iph_dialog_height);
@@ -285,4 +285,4 @@
                     assertEquals(textSideMargin, realMargins.leftMargin);
                 });
     }
-}
\ No newline at end of file
+}
diff --git a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinderTest.java b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinderTest.java
index ec8ec02..15ba449 100644
--- a/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinderTest.java
+++ b/chrome/android/features/tab_ui/javatests/src/org/chromium/chrome/browser/tasks/tab_management/TabGridPanelViewBinderTest.java
@@ -62,26 +62,29 @@
     @Override
     public void setUpTest() throws Exception {
         super.setUpTest();
-        FrameLayout parentView = new FrameLayout(getActivity());
-        mContentView = (TabListRecyclerView) LayoutInflater.from(getActivity())
-                               .inflate(R.layout.tab_list_recycler_view_layout, parentView, false);
-        mContentView.setLayoutManager(new GridLayoutManager(getActivity(), 2));
-        mToolbarView = (TabGroupUiToolbarView) LayoutInflater.from(getActivity())
-                               .inflate(R.layout.bottom_tab_grid_toolbar, mContentView, false);
-        mTabGridDialogParent =
-                new TabGridDialogParent(getActivity(), new FrameLayout(getActivity()));
-        mTabGridDialogParentView = mTabGridDialogParent.getTabGridDialogParentViewForTesting();
-        mLeftButton = mToolbarView.findViewById(R.id.toolbar_left_button);
-        mRightButton = mToolbarView.findViewById(R.id.toolbar_right_button);
-        mTitleTextView = mToolbarView.findViewById(R.id.title);
-        mMainContent = mToolbarView.findViewById(R.id.main_content);
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            FrameLayout parentView = new FrameLayout(getActivity());
+            mContentView =
+                    (TabListRecyclerView) LayoutInflater.from(getActivity())
+                            .inflate(R.layout.tab_list_recycler_view_layout, parentView, false);
+            mContentView.setLayoutManager(new GridLayoutManager(getActivity(), 2));
+            mToolbarView = (TabGroupUiToolbarView) LayoutInflater.from(getActivity())
+                                   .inflate(R.layout.bottom_tab_grid_toolbar, mContentView, false);
+            mTabGridDialogParent =
+                    new TabGridDialogParent(getActivity(), new FrameLayout(getActivity()));
+            mTabGridDialogParentView = mTabGridDialogParent.getTabGridDialogParentViewForTesting();
+            mLeftButton = mToolbarView.findViewById(R.id.toolbar_left_button);
+            mRightButton = mToolbarView.findViewById(R.id.toolbar_right_button);
+            mTitleTextView = mToolbarView.findViewById(R.id.title);
+            mMainContent = mToolbarView.findViewById(R.id.main_content);
 
-        mModel = new PropertyModel(TabGridPanelProperties.ALL_KEYS);
+            mModel = new PropertyModel(TabGridPanelProperties.ALL_KEYS);
 
-        mMCP = PropertyModelChangeProcessor.create(mModel,
-                new TabGridPanelViewBinder.ViewHolder(
-                        mToolbarView, mContentView, mTabGridDialogParent),
-                TabGridPanelViewBinder::bind);
+            mMCP = PropertyModelChangeProcessor.create(mModel,
+                    new TabGridPanelViewBinder.ViewHolder(
+                            mToolbarView, mContentView, mTabGridDialogParent),
+                    TabGridPanelViewBinder::bind);
+        });
     }
 
     @Test
diff --git a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/AndroidVSyncHelper.java b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/AndroidVSyncHelper.java
index 35da919f..6f8eb32 100644
--- a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/AndroidVSyncHelper.java
+++ b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/AndroidVSyncHelper.java
@@ -6,12 +6,12 @@
 
 import android.content.Context;
 import android.view.Choreographer;
-import android.view.WindowManager;
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
+import org.chromium.ui.display.DisplayAndroidManager;
 
 /**
  * Helper class for interfacing with the Android Choreographer from native code.
@@ -51,9 +51,7 @@
     @CalledByNative
     private float getRefreshRate() {
         Context context = ContextUtils.getApplicationContext();
-        WindowManager windowManager =
-                (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
-        return windowManager.getDefaultDisplay().getRefreshRate();
+        return DisplayAndroidManager.getDefaultDisplayForContext(context).getRefreshRate();
     }
 
     @NativeMethods
diff --git a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java
index 09aaa93..4bbf80d 100644
--- a/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java
+++ b/chrome/android/features/vr/java/src/org/chromium/chrome/browser/vr/VrShell.java
@@ -67,6 +67,7 @@
 import org.chromium.ui.base.PermissionCallback;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.display.DisplayAndroid;
+import org.chromium.ui.display.DisplayAndroidManager;
 import org.chromium.ui.display.VirtualDisplayAndroid;
 import org.chromium.ui.modaldialog.DialogDismissalCause;
 import org.chromium.ui.modaldialog.ModalDialogManager;
@@ -395,7 +396,7 @@
         // Get physical and pixel size of the display, which is needed by native
         // to dynamically calculate the content's resolution and window size.
         DisplayMetrics dm = new DisplayMetrics();
-        mActivity.getWindowManager().getDefaultDisplay().getRealMetrics(dm);
+        DisplayAndroidManager.getDefaultDisplayForContext(mActivity).getRealMetrics(dm);
         // We're supposed to be in landscape at this point, but it's possible for us to get here
         // before the change has fully propagated. In this case, the width and height are swapped,
         // which causes an incorrect display size to be used, and the page to appear zoomed in.
diff --git a/chrome/android/java/res/layout/start_top_toolbar.xml b/chrome/android/java/res/layout/start_top_toolbar.xml
index d501dae..aeb43ac 100644
--- a/chrome/android/java/res/layout/start_top_toolbar.xml
+++ b/chrome/android/java/res/layout/start_top_toolbar.xml
@@ -18,7 +18,7 @@
         android:layout_centerVertical="true"
         android:layout_alignParentStart="true"
         android:paddingStart="16dp"
-        android:paddingEnd="16dp"
+        android:paddingEnd="8dp"
         android:thumb="@drawable/incognito_switch"
         android:track="@drawable/incognito_switch_track"
         android:visibility="gone"/>
@@ -43,10 +43,17 @@
         android:layout_width="wrap_content"
         android:layout_toStartOf="@+id/menu_anchor"
         android:layout_centerVertical="true"
-        android:paddingStart="16dp"
-        android:paddingEnd="16dp"
+        android:paddingStart="8dp"
+        android:paddingEnd="8dp"
         android:contentDescription="@string/accessibility_toolbar_btn_new_tab" />
 
+    <include
+        layout="@layout/experimental_toolbar_button"
+        android:id="@+id/experimental_toolbar_button_start"
+        android:layout_toStartOf="@+id/menu_anchor"
+        style="@style/ToolbarButton"
+        android:visibility="gone" />
+
     <FrameLayout
       android:id="@+id/menu_anchor"
       android:layout_width="wrap_content"
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml
index f862afe..8da8b55f 100644
--- a/chrome/android/java/res/values/dimens.xml
+++ b/chrome/android/java/res/values/dimens.xml
@@ -320,6 +320,10 @@
          24dp is needed to completely round the corners. -->
     <dimen name="modern_toolbar_background_corner_radius">24dp</dimen>
 
+    <!-- Start surface toolbar dimensions -->
+    <dimen name="start_surface_toolbar_button_padding_to_button">8dp</dimen>
+    <dimen name="start_surface_toolbar_button_padding_to_edge">16dp</dimen>
+
     <!-- Omnibox suggestions -->
     <dimen name="omnibox_suggestion_height">60dp</dimen>
     <dimen name="omnibox_suggestion_answer_height">72dp</dimen>
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index 0ce3d5a..d23cdbbd 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -2002,7 +2002,7 @@
         }
 
         if (id == R.id.preferences_id) {
-            SettingsLauncher.getInstance().launchSettingsPage(this, null);
+            SettingsLauncher.getInstance().launchSettingsPage(this);
             RecordUserAction.record("MobileMenuSettings");
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityBrowserControlsVisibilityManager.java b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityBrowserControlsVisibilityManager.java
index c4a17a0e..07e7414 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityBrowserControlsVisibilityManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityBrowserControlsVisibilityManager.java
@@ -5,6 +5,7 @@
 package org.chromium.chrome.browser.browserservices.trustedwebactivityui.controller;
 
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 
 import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.customtabs.CloseButtonVisibilityManager;
@@ -13,8 +14,8 @@
 import org.chromium.chrome.browser.customtabs.content.TabObserverRegistrar.CustomTabTabObserver;
 import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarCoordinator;
 import org.chromium.chrome.browser.dependency_injection.ActivityScope;
+import org.chromium.chrome.browser.ssl.SecurityStateModel;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tab.TabImpl;
 import org.chromium.chrome.browser.webapps.WebDisplayMode;
 import org.chromium.chrome.browser.webapps.WebappExtras;
 import org.chromium.components.security_state.ConnectionSecurityLevel;
@@ -123,8 +124,7 @@
     private @BrowserControlsState int computeBrowserControlsState(@Nullable Tab tab) {
         // Force browser controls to show when the security level is dangerous for consistency with
         // TabStateBrowserControlsVisibilityDelegate.
-        if (tab != null
-                && ((TabImpl) tab).getSecurityLevel() == ConnectionSecurityLevel.DANGEROUS) {
+        if (tab != null && getSecurityLevel(tab) == ConnectionSecurityLevel.DANGEROUS) {
             return BrowserControlsState.SHOWN;
         }
 
@@ -139,4 +139,10 @@
     private boolean isChildTab(@Nullable Tab tab) {
         return tab != null && tab.getParentId() != Tab.INVALID_TAB_ID;
     }
+
+    @ConnectionSecurityLevel
+    @VisibleForTesting
+    int getSecurityLevel(Tab tab) {
+        return SecurityStateModel.getSecurityLevelForWebContents(tab.getWebContents());
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
index 34a09fa0..9a982f3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -54,8 +54,8 @@
 import org.chromium.chrome.browser.night_mode.SystemNightModeMonitor;
 import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
 import org.chromium.chrome.browser.page_info.PageInfoController;
+import org.chromium.chrome.browser.previews.Previews;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tab.TabImpl;
 import org.chromium.chrome.browser.ui.appmenu.AppMenuPropertiesDelegate;
 import org.chromium.chrome.browser.usage_stats.UsageStatsService;
 import org.chromium.chrome.browser.util.IntentUtils;
@@ -366,10 +366,7 @@
             return false;
         }
 
-        Tab tab = mTabProvider.getTab();
-        if (tab != null && ((TabImpl) tab).isPreview()) {
-            return false;
-        }
+        if (Previews.isPreview(mTabProvider.getTab())) return false;
 
         String publisherUrlPackage = mConnection.getTrustedCdnPublisherUrlPackage();
         return publisherUrlPackage != null
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabNavigationEventObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabNavigationEventObserver.java
index 7b339eb..1e35418 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabNavigationEventObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabNavigationEventObserver.java
@@ -9,12 +9,11 @@
 
 import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.dependency_injection.ActivityScope;
+import org.chromium.chrome.browser.ssl.SecurityStateModel;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabHidingType;
-import org.chromium.chrome.browser.tab.TabImpl;
 import org.chromium.chrome.browser.tab.TabSelectionType;
-import org.chromium.components.security_state.ConnectionSecurityLevel;
 
 import javax.inject.Inject;
 
@@ -65,7 +64,7 @@
 
     @Override
     public void onDidAttachInterstitialPage(Tab tab) {
-        if (((TabImpl) tab).getSecurityLevel() != ConnectionSecurityLevel.DANGEROUS) return;
+        if (SecurityStateModel.isContentDangerous(tab.getWebContents())) return;
         mConnection.notifyNavigationEvent(mSessionToken, CustomTabsCallback.NAVIGATION_FAILED);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java
index 5ec9d221..4b838ca 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabObserver.java
@@ -22,12 +22,11 @@
 import org.chromium.chrome.browser.dependency_injection.ActivityScope;
 import org.chromium.chrome.browser.prerender.ExternalPrerenderHandler;
 import org.chromium.chrome.browser.share.ShareHelper;
+import org.chromium.chrome.browser.ssl.SecurityStateModel;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabHidingType;
-import org.chromium.chrome.browser.tab.TabImpl;
 import org.chromium.chrome.browser.tab.TabObserver;
-import org.chromium.components.security_state.ConnectionSecurityLevel;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.NavigationHandle;
 
@@ -180,7 +179,7 @@
 
     @Override
     public void onDidAttachInterstitialPage(Tab tab) {
-        if (((TabImpl) tab).getSecurityLevel() != ConnectionSecurityLevel.DANGEROUS) return;
+        if (SecurityStateModel.isContentDangerous(tab.getWebContents())) return;
         resetPageLoadTracking();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabStatusBarColorProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabStatusBarColorProvider.java
index a868bdfe..20e0add 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabStatusBarColorProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabStatusBarColorProvider.java
@@ -7,10 +7,13 @@
 import static org.chromium.chrome.browser.ui.system.StatusBarColorController.DEFAULT_STATUS_BAR_COLOR;
 import static org.chromium.chrome.browser.ui.system.StatusBarColorController.UNDEFINED_STATUS_BAR_COLOR;
 
+import androidx.annotation.VisibleForTesting;
+
 import org.chromium.chrome.browser.browserservices.BrowserServicesIntentDataProvider;
 import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarColorController;
 import org.chromium.chrome.browser.customtabs.features.toolbar.CustomTabToolbarColorController.ToolbarColorType;
 import org.chromium.chrome.browser.dependency_injection.ActivityScope;
+import org.chromium.chrome.browser.previews.Previews;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.ui.system.StatusBarColorController;
 
@@ -49,7 +52,7 @@
 
         @ToolbarColorType
         int toolbarColorType = CustomTabToolbarColorController.computeToolbarColorType(
-                mIntentDataProvider, mUseTabThemeColor, tab);
+                mIntentDataProvider, mUseTabThemeColor, tab, () -> isPreview(tab));
         switch (toolbarColorType) {
             case ToolbarColorType.THEME_COLOR:
                 return UNDEFINED_STATUS_BAR_COLOR;
@@ -60,4 +63,9 @@
         }
         return DEFAULT_STATUS_BAR_COLOR;
     }
+
+    @VisibleForTesting
+    boolean isPreview(Tab tab) {
+        return Previews.isPreview(tab);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionHelper.java
index 7452d36..9c8ced1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabTaskDescriptionHelper.java
@@ -24,13 +24,13 @@
 import org.chromium.chrome.browser.lifecycle.ActivityLifecycleDispatcher;
 import org.chromium.chrome.browser.lifecycle.Destroyable;
 import org.chromium.chrome.browser.lifecycle.NativeInitObserver;
+import org.chromium.chrome.browser.ssl.SecurityStateModel;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabImpl;
 import org.chromium.chrome.browser.tab.TabThemeColorHelper;
 import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.chrome.browser.util.UrlUtilities;
 import org.chromium.chrome.browser.webapps.WebappExtras;
-import org.chromium.components.security_state.ConnectionSecurityLevel;
 import org.chromium.content_public.browser.NavigationHandle;
 
 import javax.inject.Inject;
@@ -179,8 +179,7 @@
                 }
 
                 private boolean hasSecurityWarningOrError(Tab tab) {
-                    int securityLevel = ((TabImpl) tab).getSecurityLevel();
-                    return securityLevel == ConnectionSecurityLevel.DANGEROUS;
+                    return SecurityStateModel.isContentDangerous(tab.getWebContents());
                 }
             };
             mTabObserverRegistrar.registerActivityTabObserver(mIconTabObserver);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/DynamicModuleNavigationEventObserver.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/DynamicModuleNavigationEventObserver.java
index 1ee962fd..8a3bdd0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/DynamicModuleNavigationEventObserver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/dynamicmodule/DynamicModuleNavigationEventObserver.java
@@ -19,12 +19,11 @@
 import androidx.annotation.VisibleForTesting;
 import androidx.browser.customtabs.CustomTabsCallback;
 
+import org.chromium.chrome.browser.ssl.SecurityStateModel;
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.browser.tab.TabHidingType;
-import org.chromium.chrome.browser.tab.TabImpl;
 import org.chromium.chrome.browser.tab.TabSelectionType;
-import org.chromium.components.security_state.ConnectionSecurityLevel;
 import org.chromium.content_public.browser.NavigationEntry;
 import org.chromium.net.NetError;
 
@@ -126,7 +125,7 @@
 
     @Override
     public void onDidAttachInterstitialPage(Tab tab) {
-        if (((TabImpl) tab).getSecurityLevel() != ConnectionSecurityLevel.DANGEROUS) return;
+        if (SecurityStateModel.isContentDangerous(tab.getWebContents())) return;
         notifyOnNavigationEvent(NAVIGATION_FAILED, getExtrasBundleForNavigationEvent(tab));
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarColorController.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarColorController.java
index 004cd7c..7212f08 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarColorController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/features/toolbar/CustomTabToolbarColorController.java
@@ -14,8 +14,8 @@
 import org.chromium.chrome.browser.customtabs.content.TabObserverRegistrar;
 import org.chromium.chrome.browser.customtabs.content.TabObserverRegistrar.CustomTabTabObserver;
 import org.chromium.chrome.browser.dependency_injection.ActivityScope;
+import org.chromium.chrome.browser.previews.Previews;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tab.TabImpl;
 import org.chromium.chrome.browser.tab.TabSelectionType;
 import org.chromium.chrome.browser.tab.TabThemeColorHelper;
 import org.chromium.chrome.browser.toolbar.ToolbarManager;
@@ -43,6 +43,12 @@
         int INTENT_TOOLBAR_COLOR = 2;
     }
 
+    /**
+     * Interface used to receive a predicate that tells if the current tab is in preview mode.
+     * This makes the {@link #computeToolbarColorType()} test-friendly.
+     */
+    public interface BooleanFunction { boolean get(); }
+
     private final BrowserServicesIntentDataProvider mIntentDataProvider;
     private final ChromeActivity mActivity;
     private final TabObserverRegistrar mTabObserverRegistrar;
@@ -67,13 +73,12 @@
      * surfaces with different values for {@link ToolbarColorType.DEFAULT_COLOR}.
      */
     public static int computeToolbarColorType(BrowserServicesIntentDataProvider intentDataProvider,
-            boolean useTabThemeColor, @Nullable Tab tab) {
+            boolean useTabThemeColor, @Nullable Tab tab, BooleanFunction isPreview) {
         if (intentDataProvider.isOpenedByChrome()) {
             return (tab == null) ? ToolbarColorType.DEFAULT_COLOR : ToolbarColorType.THEME_COLOR;
         }
 
-        if (shouldUseDefaultThemeColorForFullscreen(intentDataProvider)
-                || (tab != null && ((TabImpl) tab).isPreview())) {
+        if (shouldUseDefaultThemeColorForFullscreen(intentDataProvider) || isPreview.get()) {
             return ToolbarColorType.DEFAULT_COLOR;
         }
 
@@ -155,7 +160,8 @@
     private int computeColor() {
         Tab tab = mTabProvider.getTab();
         @ToolbarColorType
-        int toolbarColorType = computeToolbarColorType(mIntentDataProvider, mUseTabThemeColor, tab);
+        int toolbarColorType = computeToolbarColorType(
+                mIntentDataProvider, mUseTabThemeColor, tab, () -> Previews.isPreview(tab));
         switch (toolbarColorType) {
             case ToolbarColorType.THEME_COLOR:
                 assert tab != null;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesSection.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesSection.java
index 51e676b1..b2472d8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExperimentalExploreSitesSection.java
@@ -4,12 +4,9 @@
 
 package org.chromium.chrome.browser.explore_sites;
 
-import android.content.Context;
 import android.graphics.Bitmap;
-import android.graphics.Point;
 import android.view.LayoutInflater;
 import android.view.View;
-import android.view.WindowManager;
 import android.widget.LinearLayout;
 
 import org.chromium.chrome.R;
@@ -17,6 +14,7 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.ui.base.PageTransition;
+import org.chromium.ui.display.DisplayAndroid;
 import org.chromium.ui.mojom.WindowOpenDisposition;
 
 import java.util.List;
@@ -61,11 +59,9 @@
         // TODO(chili): Try to get this from view hierarchy. This gets called before the
         // mExploreSection is measured when opening ntp via 3 dot menu -> new tab,
         // causing a crash. Max width is set to tile grid max width.
-        Point screenSize = new Point();
-        ((WindowManager) mExploreSection.getContext().getSystemService(Context.WINDOW_SERVICE))
-                .getDefaultDisplay()
-                .getSize(screenSize);
-        int tileWidth = Math.min(screenSize.x,
+        int width =
+                DisplayAndroid.getNonMultiDisplay(mExploreSection.getContext()).getDisplayWidth();
+        int tileWidth = Math.min(width,
                                 mExploreSection.getResources().getDimensionPixelSize(
                                         R.dimen.tile_grid_layout_max_width))
                 / MAX_TILES;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java
index f15b561..fe9c8c5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/explore_sites/ExploreSitesBridge.java
@@ -4,10 +4,7 @@
 
 package org.chromium.chrome.browser.explore_sites;
 
-import android.content.Context;
 import android.graphics.Bitmap;
-import android.util.DisplayMetrics;
-import android.view.WindowManager;
 
 import org.chromium.base.Callback;
 import org.chromium.base.ContextUtils;
@@ -15,6 +12,7 @@
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.base.annotations.NativeMethods;
 import org.chromium.chrome.browser.profiles.Profile;
+import org.chromium.ui.display.DisplayAndroid;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -154,14 +152,8 @@
      */
     @CalledByNative
     static float getScaleFactorFromDevice() {
-        // Get DeviceMetrics from context.
-        DisplayMetrics metrics = new DisplayMetrics();
-        ((WindowManager) ContextUtils.getApplicationContext().getSystemService(
-                 Context.WINDOW_SERVICE))
-                .getDefaultDisplay()
-                .getMetrics(metrics);
-        // Get density and return it.
-        return metrics.density;
+        return DisplayAndroid.getNonMultiDisplay(ContextUtils.getApplicationContext())
+                .getDipScale();
     }
 
     @NativeMethods
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotMonitor.java b/chrome/android/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotMonitor.java
index 856df95..3e4fb583 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotMonitor.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/feature_engagement/ScreenshotMonitor.java
@@ -5,7 +5,6 @@
 package org.chromium.chrome.browser.feature_engagement;
 
 import android.Manifest;
-import android.content.Context;
 import android.content.pm.PackageManager;
 import android.database.ContentObserver;
 import android.database.Cursor;
@@ -14,8 +13,6 @@
 import android.provider.MediaStore;
 import android.provider.MediaStore.Images.Media;
 import android.support.v4.content.ContextCompat;
-import android.util.DisplayMetrics;
-import android.view.WindowManager;
 
 import androidx.annotation.VisibleForTesting;
 
@@ -25,6 +22,7 @@
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.base.task.PostTask;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
+import org.chromium.ui.display.DisplayAndroid;
 
 /**
  * This class detects screenshots by monitoring the screenshots directory on internal and external
@@ -153,13 +151,10 @@
         }
 
         // Check width and height.
-        DisplayMetrics displayMetrics = new DisplayMetrics();
-        WindowManager windowManager =
-                (WindowManager) ContextUtils.getApplicationContext().getSystemService(
-                        Context.WINDOW_SERVICE);
-        windowManager.getDefaultDisplay().getMetrics(displayMetrics);
-        int screenHeight = displayMetrics.heightPixels;
-        int screenWidth = displayMetrics.widthPixels;
+        DisplayAndroid display =
+                DisplayAndroid.getNonMultiDisplay(ContextUtils.getApplicationContext());
+        int screenHeight = display.getDisplayWidth();
+        int screenWidth = display.getDisplayHeight();
         int imageHeight = Integer.parseInt(imageHeightString);
         int imageWidth = Integer.parseInt(imageWidthString);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ToSAckedReceiver.java b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ToSAckedReceiver.java
index e278aade..1552b85 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ToSAckedReceiver.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/firstrun/ToSAckedReceiver.java
@@ -7,17 +7,16 @@
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.SharedPreferences;
 import android.os.Build;
 import android.os.Bundle;
 
-import org.chromium.base.ContextUtils;
 import org.chromium.base.task.PostTask;
 import org.chromium.chrome.browser.init.ProcessInitializationHandler;
+import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
+import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
 import org.chromium.components.signin.AccountManagerFacade;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
 
-import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
@@ -26,7 +25,6 @@
  * the Chrome ToS so that we don't show the ToS string during our first run.
  */
 public class ToSAckedReceiver extends BroadcastReceiver {
-    static final String TOS_ACKED_ACCOUNTS = "ToS acknowledged accounts";
     static final String EXTRA_ACCOUNT_NAME = "TosAckedReceiver.account";
 
     @Override
@@ -38,13 +36,8 @@
         String accountName = args.getString(EXTRA_ACCOUNT_NAME, null);
         if (accountName == null) return;
 
-        SharedPreferences prefs = ContextUtils.getAppSharedPreferences();
-        // Make sure to construct a new set so it can be modified safely. See crbug.com/568369.
-        Set<String> accounts =
-                new HashSet<String>(prefs.getStringSet(TOS_ACKED_ACCOUNTS, new HashSet<String>()));
-        accounts.add(accountName);
-        prefs.edit().remove(TOS_ACKED_ACCOUNTS).apply();
-        prefs.edit().putStringSet(TOS_ACKED_ACCOUNTS, accounts).apply();
+        SharedPreferencesManager prefs = SharedPreferencesManager.getInstance();
+        prefs.addToStringSet(ChromePreferenceKeys.TOS_ACKED_ACCOUNTS, accountName);
     }
 
     /**
@@ -54,9 +47,8 @@
     public static boolean checkAnyUserHasSeenToS() {
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) return false;
 
-        Set<String> toSAckedAccounts =
-                ContextUtils.getAppSharedPreferences().getStringSet(
-                        TOS_ACKED_ACCOUNTS, null);
+        Set<String> toSAckedAccounts = SharedPreferencesManager.getInstance().readStringSet(
+                ChromePreferenceKeys.TOS_ACKED_ACCOUNTS, null);
         if (toSAckedAccounts == null || toSAckedAccounts.isEmpty()) return false;
         PostTask.runSynchronously(UiThreadTaskTraits.DEFAULT,
                 () -> { ProcessInitializationHandler.getInstance().initializePreNative(); });
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index c10593f..cd9e7b2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -332,7 +332,6 @@
     public static final String SEND_TAB_TO_SELF = "SyncSendTabToSelf";
     public static final String SERVICE_MANAGER_FOR_DOWNLOAD = "ServiceManagerForDownload";
     public static final String SERVICE_WORKER_PAYMENT_APPS = "ServiceWorkerPaymentApps";
-    public static final String SETTINGS_MODERN_STATUS_BAR = "SettingsModernStatusBar";
     public static final String SHARED_CLIPBOARD_UI = "SharedClipboardUI";
     public static final String SHARING_QR_CODE_ANDROID = "SharingQrCodeAndroid";
     public static final String SHOPPING_ASSIST = "ShoppingAssist";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/HistoryNavigationCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/HistoryNavigationCoordinator.java
index cc8b622..01399b06 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/HistoryNavigationCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/HistoryNavigationCoordinator.java
@@ -65,6 +65,11 @@
                 initNavigationHandler(
                         tab, createDelegate(tab), tab.getWebContents(), tab.isNativePage());
             }
+
+            @Override
+            public void onDestroyed(Tab tab) {
+                mTab = null;
+            }
         };
 
         // We wouldn't hear about the first tab until the content changed or we switched tabs
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
index 74944e13..da378c1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/PaymentRequestImpl.java
@@ -42,7 +42,6 @@
 import org.chromium.chrome.browser.payments.ui.SectionInformation;
 import org.chromium.chrome.browser.payments.ui.ShoppingCart;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.settings.MainPreferences;
 import org.chromium.chrome.browser.settings.SettingsLauncher;
 import org.chromium.chrome.browser.ssl.SecurityStateModel;
 import org.chromium.chrome.browser.tab.Tab;
@@ -2282,7 +2281,7 @@
             return;
         }
 
-        SettingsLauncher.getInstance().launchSettingsPage(context, MainPreferences.class);
+        SettingsLauncher.getInstance().launchSettingsPage(context);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerMediator.java
index ea1ff1d..7d95bb80 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerMediator.java
@@ -26,6 +26,7 @@
 /* package */ class PaymentHandlerMediator
         extends WebContentsObserver implements BottomSheetObserver, PaymentHandlerToolbarObserver {
     private final PropertyModel mModel;
+    // Whenever invoked, invoked outside of the WebContentsObserver callbacks.
     private final Runnable mHider;
     // Postfixed with "Ref" to distinguish from mWebContent in WebContentsObserver. Although
     // referencing the same object, mWebContentsRef is preferable to WebContents here because
@@ -33,6 +34,8 @@
     // null.
     private final WebContents mWebContentsRef;
     private final PaymentHandlerUiObserver mPaymentHandlerUiObserver;
+    // Used to postpone execution of a callback to avoid destroy objects (e.g., WebContents) in
+    // their own methods.
     private final Handler mHandler = new Handler();
 
     /**
@@ -54,6 +57,14 @@
         mPaymentHandlerUiObserver = observer;
     }
 
+    private void closeUIForInsecureNavigation() {
+        mHandler.post(() -> {
+            ServiceWorkerPaymentAppBridge.onClosingPaymentAppWindowForInsecureNavigation(
+                    mWebContentsRef);
+            mHider.run();
+        });
+    }
+
     // BottomSheetObserver:
     @Override
     public void onSheetStateChanged(@SheetState int newState) {
@@ -91,25 +102,23 @@
     @Override
     public void didFinishLoad(long frameId, String validatedUrl, boolean isMainFrame) {
         if (!SslValidityChecker.isValidPageInPaymentHandlerWindow(mWebContentsRef)) {
-            ServiceWorkerPaymentAppBridge.onClosingPaymentAppWindowForInsecureNavigation(
-                    mWebContentsRef);
-            mHandler.post(mHider);
+            closeUIForInsecureNavigation();
         }
     }
 
     @Override
     public void didAttachInterstitialPage() {
-        ServiceWorkerPaymentAppBridge.onClosingPaymentAppWindowForInsecureNavigation(
-                mWebContentsRef);
-        mHandler.post(mHider);
+        closeUIForInsecureNavigation();
     }
 
     @Override
     public void didFailLoad(
             boolean isMainFrame, int errorCode, String description, String failingUrl) {
-        // TODO(crbug.com/1017926): Respond to service worker with the net error.
-        ServiceWorkerPaymentAppBridge.onClosingPaymentAppWindow(mWebContentsRef);
-        mHandler.post(mHider);
+        mHandler.post(() -> {
+            // TODO(crbug.com/1017926): Respond to service worker with the net error.
+            ServiceWorkerPaymentAppBridge.onClosingPaymentAppWindow(mWebContentsRef);
+            mHider.run();
+        });
     }
 
     // PaymentHandlerToolbarObserver:
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerView.java b/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerView.java
index eb5f932b..aa62f1b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/payments/handler/PaymentHandlerView.java
@@ -18,6 +18,7 @@
 import org.chromium.chrome.browser.thinwebview.ThinWebViewFactory;
 import org.chromium.chrome.browser.widget.bottomsheet.BottomSheetContent;
 import org.chromium.components.embedder_support.view.ContentView;
+import org.chromium.content_public.browser.RenderCoordinates;
 import org.chromium.content_public.browser.WebContents;
 import org.chromium.ui.base.ActivityWindowAndroid;
 
@@ -26,6 +27,7 @@
     private final View mToolbarView;
     private final FrameLayout mContentView;
     private final ThinWebView mThinWebView;
+    private final WebContents mWebContents;
     private final Handler mReflowHandler = new Handler();
     private final int mTabHeight;
     private final int mToolbarHeightPx;
@@ -39,6 +41,7 @@
      */
     /* package */ PaymentHandlerView(ChromeActivity activity, WebContents webContents,
             ContentView webContentView, View toolbarView) {
+        mWebContents = webContents;
         mTabHeight = activity.getActivityTab().getView().getHeight();
         mToolbarView = toolbarView;
         mToolbarHeightPx =
@@ -107,7 +110,9 @@
 
     @Override
     public int getVerticalScrollOffset() {
-        return 0;
+        return mWebContents == null
+                ? 0
+                : RenderCoordinates.fromWebContents(mWebContents).getScrollYPixInt();
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/previews/Previews.java b/chrome/android/java/src/org/chromium/chrome/browser/previews/Previews.java
new file mode 100644
index 0000000..cfcdbc4d
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/previews/Previews.java
@@ -0,0 +1,26 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.previews;
+
+import org.chromium.chrome.browser.ssl.SecurityStateModel;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.content_public.browser.WebContents;
+
+/**
+ * Class for preview-related util methods.
+ */
+public final class Previews {
+    /**
+     * @param tab Tab object containing the WebContents.
+     * @return {@code true} if the page being displayed is a preview.
+     */
+    public static boolean isPreview(Tab tab) {
+        if (tab == null || tab.isNativePage()) return false;
+        WebContents webContents = tab.getWebContents();
+        return webContents != null && !webContents.isShowingInterstitialPage()
+                && !SecurityStateModel.isContentDangerous(webContents)
+                && PreviewsAndroidBridge.getInstance().shouldShowPreviewUI(webContents);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java
index f158b056..b0ad47d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsActivity.java
@@ -30,7 +30,6 @@
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.ChromeBaseAppCompatActivity;
-import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.help.HelpAndFeedback;
 import org.chromium.chrome.browser.init.ChromeBrowserInitializer;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -296,10 +295,6 @@
         // On P+, the status bar color is set via the XML theme.
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) return;
 
-        // Kill switch included due to past crashes when programmatically setting status bar color:
-        // https://crbug.com/880694.
-        if (!ChromeFeatureList.isEnabled(ChromeFeatureList.SETTINGS_MODERN_STATUS_BAR)) return;
-
         if (UiUtils.isSystemUiThemingDisabled()) return;
 
         // Dark status icons only supported on M+.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsLauncher.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsLauncher.java
index 33b8db6..5953af8b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsLauncher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/SettingsLauncher.java
@@ -38,6 +38,15 @@
     }
 
     /**
+     * Launches the top-level settings page.
+     *
+     * @param context The current Activity, or an application context if no Activity is available.
+     */
+    public void launchSettingsPage(Context context) {
+        launchSettingsPage(context, null);
+    }
+
+    /**
      * Launches settings, either on the top-level page or on a subpage.
      *
      * @param context The current Activity, or an application context if no Activity is available.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/settings/website/CookieControlsBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/settings/website/CookieControlsBridge.java
new file mode 100644
index 0000000..e66c523
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/settings/website/CookieControlsBridge.java
@@ -0,0 +1,72 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.settings.website;
+
+import org.chromium.base.annotations.CalledByNative;
+import org.chromium.base.annotations.NativeMethods;
+import org.chromium.content_public.browser.WebContents;
+
+/**
+ * Communicates between CookieControlsController (C++ backend) and PageInfoView (Java UI).
+ */
+public class CookieControlsBridge {
+    /**
+     * Interface for a class that wants to receive cookie updates from CookieControlsBridge.
+     */
+    public interface CookieControlsView {
+        /**
+         * Called when the cookie blocking status for the current page changes.
+         * @param status An enum indicating the cookie blocking status.
+         */
+        public void onCookieBlockingStatusChanged(@CookieControlsControllerStatus int status);
+
+        /**
+         * Called when there is an update in the cookies that are currently being blocked.
+         * @param blockedCookies An integer indicating the number of cookies being blocked.
+         */
+        public void onBlockedCookiesCountChanged(int blockedCookies);
+    }
+
+    private long mNativeCookieControlsBridge;
+    private CookieControlsView mObserver;
+
+    /**
+     * Initializes a CookieControlsBridge instance.
+     * @param observer An observer to call with updates from the cookie controller.
+     * @param webContents The WebContents instance to observe.
+     */
+    public CookieControlsBridge(CookieControlsView observer, WebContents webContents) {
+        mObserver = observer;
+        mNativeCookieControlsBridge =
+                CookieControlsBridgeJni.get().init(CookieControlsBridge.this, webContents);
+    }
+
+    /**
+     * Destroys the native counterpart of this class.
+     */
+    public void destroy() {
+        if (mNativeCookieControlsBridge != 0) {
+            CookieControlsBridgeJni.get().destroy(
+                    mNativeCookieControlsBridge, CookieControlsBridge.this);
+            mNativeCookieControlsBridge = 0;
+        }
+    }
+
+    @CalledByNative
+    private void onCookieBlockingStatusChanged(@CookieControlsControllerStatus int status) {
+        mObserver.onCookieBlockingStatusChanged(status);
+    }
+
+    @CalledByNative
+    private void onBlockedCookiesCountChanged(int blockedCookies) {
+        mObserver.onBlockedCookiesCountChanged(blockedCookies);
+    }
+
+    @NativeMethods
+    interface Natives {
+        long init(CookieControlsBridge caller, WebContents webContents);
+        void destroy(long nativeCookieControlsBridge, CookieControlsBridge caller);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardShareActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardShareActivity.java
index fc3776e..f959e65 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardShareActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sharing/shared_clipboard/SharedClipboardShareActivity.java
@@ -79,7 +79,7 @@
             chromeSettingsButton.setVisibility(View.VISIBLE);
             chromeSettingsButton.setOnClickListener(view -> {
                 SettingsLauncher.getInstance().launchSettingsPage(
-                        ContextUtils.getApplicationContext(), null);
+                        ContextUtils.getApplicationContext());
             });
         }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ssl/SecurityStateModel.java b/chrome/android/java/src/org/chromium/chrome/browser/ssl/SecurityStateModel.java
index 35218b96..a823479 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ssl/SecurityStateModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ssl/SecurityStateModel.java
@@ -27,6 +27,10 @@
         return SecurityStateModelJni.get().getSecurityLevelForWebContents(webContents);
     }
 
+    public static boolean isContentDangerous(WebContents webContents) {
+        return getSecurityLevelForWebContents(webContents) == ConnectionSecurityLevel.DANGEROUS;
+    }
+
     /**
      * Returns whether to use a danger icon instead of an info icon in the URL bar for the WARNING
      * security level.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS b/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
index 913f8b5..28d1044 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/DEPS
@@ -4,6 +4,8 @@
   "+chrome/android/java/src/org/chromium/chrome/browser/TabHidingType.java",
   "+chrome/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java",
   "+chrome/android/java/src/org/chromium/chrome/browser/incognito/IncognitoUtils.java",
+  "+chrome/android/java/src/org/chromium/chrome/browser/previews/Previews.java",
+  "+chrome/android/java/src/org/chromium/chrome/browser/ssl/SecurityStateModel.java",
   "+chrome/android/java/src/org/chromium/chrome/browser/tab",
   "+chrome/android/java/src/org/chromium/chrome/browser/webapps/WebDisplayMode.java",
   "+chrome/browser/preferences",
@@ -28,9 +30,7 @@
     "+chrome/android/java/src/org/chromium/chrome/browser/native_page/NativePageFactory.java",
     "+chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageUtils.java",
     "+chrome/android/java/src/org/chromium/chrome/browser/prerender/ExternalPrerenderHandler.java",
-    "+chrome/android/java/src/org/chromium/chrome/browser/previews/PreviewsAndroidBridge.java",
     "+chrome/android/java/src/org/chromium/chrome/browser/rlz/RevenueStats.java",
-    "+chrome/android/java/src/org/chromium/chrome/browser/ssl/SecurityStateModel.java",
     "+chrome/android/java/src/org/chromium/chrome/browser/night_mode",
     "+chrome/android/public/profiles/java/src/org/chromium/chrome/browser/profiles/Profile.java",
     "+chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/UrlConstants.java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
index 8a9e7d8..80935d70 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabImpl.java
@@ -39,17 +39,14 @@
 import org.chromium.chrome.browser.night_mode.NightModeUtils;
 import org.chromium.chrome.browser.offlinepages.OfflinePageUtils;
 import org.chromium.chrome.browser.prerender.ExternalPrerenderHandler;
-import org.chromium.chrome.browser.previews.PreviewsAndroidBridge;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.rlz.RevenueStats;
-import org.chromium.chrome.browser.ssl.SecurityStateModel;
 import org.chromium.chrome.browser.tab.TabState.WebContentsState;
 import org.chromium.chrome.browser.tab.TabUma.TabCreationState;
 import org.chromium.chrome.browser.util.UrlConstants;
 import org.chromium.chrome.browser.vr.VrModuleProvider;
 import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
 import org.chromium.components.embedder_support.view.ContentView;
-import org.chromium.components.security_state.ConnectionSecurityLevel;
 import org.chromium.content_public.browser.ChildProcessImportance;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.WebContents;
@@ -724,23 +721,6 @@
     }
 
     /**
-     * @return If the page being displayed is a Preview
-     */
-    public boolean isPreview() {
-        return getWebContents() != null && !isNativePage() && !isShowingInterstitialPage()
-                && getSecurityLevel() != ConnectionSecurityLevel.DANGEROUS
-                && PreviewsAndroidBridge.getInstance().shouldShowPreviewUI(getWebContents());
-    }
-
-    /**
-     * @return The current {@link ConnectionSecurityLevel} for the tab.
-     */
-    // TODO(tedchoc): Remove this and transition all clients to use LocationBarModel directly.
-    public int getSecurityLevel() {
-        return SecurityStateModel.getSecurityLevelForWebContents(getWebContents());
-    }
-
-    /**
      * @return Original url of the tab, which is the original url from DOMDistiller.
      */
     public String getOriginalUrl() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabStateBrowserControlsVisibilityDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabStateBrowserControlsVisibilityDelegate.java
index b6a637a..5c785a36 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabStateBrowserControlsVisibilityDelegate.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabStateBrowserControlsVisibilityDelegate.java
@@ -10,10 +10,10 @@
 
 import org.chromium.chrome.browser.device.DeviceClassManager;
 import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.ssl.SecurityStateModel;
 import org.chromium.chrome.browser.util.AccessibilityUtil;
 import org.chromium.chrome.browser.util.UrlConstants;
 import org.chromium.components.dom_distiller.core.DomDistillerUrlUtils;
-import org.chromium.components.security_state.ConnectionSecurityLevel;
 import org.chromium.content_public.browser.ImeAdapter;
 import org.chromium.content_public.browser.ImeEventObserver;
 import org.chromium.content_public.browser.NavigationHandle;
@@ -191,9 +191,8 @@
         enableHidingBrowserControls &= !url.startsWith(UrlConstants.CHROME_URL_PREFIX);
         enableHidingBrowserControls &= !url.startsWith(UrlConstants.CHROME_NATIVE_URL_PREFIX);
 
-        int securityState = mTab.getSecurityLevel();
-        enableHidingBrowserControls &= (securityState != ConnectionSecurityLevel.DANGEROUS);
-
+        enableHidingBrowserControls &=
+                !SecurityStateModel.isContentDangerous(mTab.getWebContents());
         enableHidingBrowserControls &=
                 !SelectionPopupController.fromWebContents(webContents).isFocusedNodeEditable();
         enableHidingBrowserControls &= !mTab.isShowingErrorPage();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabThemeColorHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabThemeColorHelper.java
index ee00bba1..3a5fa73 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/tab/TabThemeColorHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/tab/TabThemeColorHelper.java
@@ -10,6 +10,8 @@
 import androidx.annotation.VisibleForTesting;
 
 import org.chromium.base.UserData;
+import org.chromium.chrome.browser.previews.Previews;
+import org.chromium.chrome.browser.ssl.SecurityStateModel;
 import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.components.browser_ui.styles.ChromeColors;
 import org.chromium.components.security_state.ConnectionSecurityLevel;
@@ -152,14 +154,15 @@
      */
     private boolean checkThemingAllowed() {
         // Do not apply the theme color if there are any security issues on the page.
-        final int securityLevel = mTab.getSecurityLevel();
+        final int securityLevel =
+                SecurityStateModel.getSecurityLevelForWebContents(mTab.getWebContents());
         return securityLevel != ConnectionSecurityLevel.DANGEROUS
                 && securityLevel != ConnectionSecurityLevel.SECURE_WITH_POLICY_INSTALLED_CERT
                 && (mTab.getActivity() == null || !mTab.getActivity().isTablet())
                 && (mTab.getActivity() == null
                         || !mTab.getActivity().getNightModeStateProvider().isInNightMode())
                 && !mTab.isNativePage() && !mTab.isShowingInterstitialPage() && !mTab.isIncognito()
-                && !mTab.isPreview();
+                && !Previews.isPreview(mTab);
     }
 
     /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/IdentityDiscController.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/IdentityDiscController.java
index 7129f75..cb70184 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/IdentityDiscController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/IdentityDiscController.java
@@ -70,7 +70,7 @@
     @IdentityDiscState
     private int mState = IdentityDiscState.NONE;
 
-    private boolean mIsNTPVisible;
+    private boolean mShouldShowButton;
 
     /**
      * Creates IdentityDiscController object.
@@ -98,23 +98,23 @@
     }
 
     /**
-     * Shows/hides Identity Disc depending on whether NTP is visible.
+     * Shows/hides Identity Disc.
      */
     void updateButtonState() {
-        updateButtonState(mIsNTPVisible);
+        updateButtonState(mShouldShowButton);
     }
 
     /**
-     * Shows/hides Identity Disc depending on whether NTP is visible.
+     * @param shouldShowButton Whether to show the Identity Disc.
      */
-    void updateButtonState(boolean isNTPVisible) {
-        mIsNTPVisible = isNTPVisible;
+    void updateButtonState(boolean shouldShowButton) {
+        mShouldShowButton = shouldShowButton;
         String accountName = ChromeSigninController.get().getSignedInAccountName();
-        boolean shouldShowIdentityDisc = isNTPVisible && accountName != null;
+        boolean canShowIdentityDisc = mShouldShowButton && accountName != null;
         @IdentityDiscState
         int oldState = mState;
 
-        mState = !shouldShowIdentityDisc
+        mState = !canShowIdentityDisc
                 ? IdentityDiscState.NONE
                 : mToolbarManager.isBottomToolbarVisible() ? IdentityDiscState.LARGE
                                                            : IdentityDiscState.SMALL;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
index 32ea61be..9456896 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
@@ -26,6 +26,7 @@
 import org.chromium.chrome.browser.omnibox.OmniboxUrlEmphasizer;
 import org.chromium.chrome.browser.omnibox.SearchEngineLogoUtils;
 import org.chromium.chrome.browser.omnibox.UrlBarData;
+import org.chromium.chrome.browser.previews.Previews;
 import org.chromium.chrome.browser.previews.PreviewsAndroidBridge;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.ssl.SecurityStateModel;
@@ -343,7 +344,7 @@
 
     @Override
     public boolean isPreview() {
-        return hasTab() && ((TabImpl) mTab).isPreview();
+        return hasTab() && Previews.isPreview(mTab);
     }
 
     @Override
@@ -377,19 +378,25 @@
 
     @VisibleForTesting
     @ConnectionSecurityLevel
-    static int getSecurityLevel(Tab tab, boolean isOfflinePage, @Nullable String publisherUrl) {
+    int getSecurityLevel(Tab tab, boolean isOfflinePage, @Nullable String publisherUrl) {
         if (tab == null || isOfflinePage) {
             return ConnectionSecurityLevel.NONE;
         }
 
-        int securityLevel = ((TabImpl) tab).getSecurityLevel();
         if (publisherUrl != null) {
-            assert securityLevel != ConnectionSecurityLevel.DANGEROUS;
+            assert getSecurityLevelFromStateModel(tab.getWebContents())
+                    != ConnectionSecurityLevel.DANGEROUS;
             return (URI.create(publisherUrl).getScheme().equals(UrlConstants.HTTPS_SCHEME))
                     ? ConnectionSecurityLevel.SECURE
                     : ConnectionSecurityLevel.WARNING;
         }
-        return securityLevel;
+        return getSecurityLevelFromStateModel(tab.getWebContents());
+    }
+
+    @VisibleForTesting
+    @ConnectionSecurityLevel
+    int getSecurityLevelFromStateModel(WebContents webContents) {
+        return SecurityStateModel.getSecurityLevelForWebContents(webContents);
     }
 
     @VisibleForTesting
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java
index b58585db..dcd52f4 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonInProductHelpController.java
@@ -18,9 +18,9 @@
 import org.chromium.chrome.browser.feature_engagement.TrackerFactory;
 import org.chromium.chrome.browser.flags.FeatureUtilities;
 import org.chromium.chrome.browser.net.spdyproxy.DataReductionProxySettings;
+import org.chromium.chrome.browser.previews.Previews;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tab.TabImpl;
 import org.chromium.chrome.browser.ui.appmenu.AppMenuCoordinator;
 import org.chromium.chrome.browser.ui.appmenu.AppMenuHandler;
 import org.chromium.chrome.browser.ui.widget.highlight.ViewHighlighter;
@@ -66,13 +66,13 @@
                         - mDataSavedOnStartPageLoad;
                 Tracker tracker = TrackerFactory.getTrackerForProfile(Profile.getLastUsedProfile());
                 if (dataSaved > 0L) tracker.notifyEvent(EventConstants.DATA_SAVED_ON_PAGE_LOAD);
-                if (((TabImpl) tab).isPreview()) {
+                if (Previews.isPreview(tab)) {
                     tracker.notifyEvent(EventConstants.PREVIEWS_PAGE_LOADED);
                 }
                 if (tab.isUserInteractable()) {
                     maybeShowDataSaverDetail();
                     if (dataSaved > 0L) maybeShowDataSaverMilestonePromo();
-                    if (((TabImpl) tab).isPreview()) maybeShowPreviewVerboseStatus();
+                    if (Previews.isPreview(tab)) maybeShowPreviewVerboseStatus();
                 }
             }
         };
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
index 98a9423e4..b87532b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarManager.java
@@ -73,6 +73,7 @@
 import org.chromium.chrome.browser.omnibox.SearchEngineLogoUtils;
 import org.chromium.chrome.browser.omnibox.UrlFocusChangeListener;
 import org.chromium.chrome.browser.partnercustomizations.HomepageManager;
+import org.chromium.chrome.browser.previews.Previews;
 import org.chromium.chrome.browser.previews.PreviewsAndroidBridge;
 import org.chromium.chrome.browser.previews.PreviewsUma;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -251,6 +252,9 @@
 
     private int mCurrentOrientation;
 
+    @OverviewModeState
+    private int mOverviewModeState = OverviewModeState.NOT_SHOWN;
+
     /**
      * Runnable for the home and search accelerator button when Start Surface home page is enabled.
      */
@@ -470,7 +474,7 @@
                 }
 
                 // TODO(crbug.com/896476): Remove this.
-                if (((TabImpl) tab).isPreview()) {
+                if (Previews.isPreview(tab)) {
                     // Some previews (like Client LoFi) are not fully decided until the page
                     // finishes loading. If this is a preview, update the security icon which will
                     // also update the verbose status view to make sure the "Lite" badge is
@@ -604,7 +608,7 @@
                     mToolbar.onNavigatedToDifferentPage();
                 }
 
-                if (navigation.hasCommitted() && ((TabImpl) tab).isPreview()) {
+                if (navigation.hasCommitted() && Previews.isPreview(tab)) {
                     // Some previews are not fully decided until the page commits. If this
                     // is a preview, update the security icon which will also update the verbose
                     // status view to make sure the "Lite" badge is displayed.
@@ -735,7 +739,11 @@
             @Override
             public void onOverviewModeStateChanged(
                     @OverviewModeState int overviewModeState, boolean showTabSwitcherToolbar) {
+                assert FeatureUtilities.isStartSurfaceEnabled();
                 mToolbar.updateTabSwitcherToolbarState(showTabSwitcherToolbar);
+                mOverviewModeState = overviewModeState;
+                mIdentityDiscController.updateButtonState(
+                        mOverviewModeState == OverviewModeState.SHOWN_HOMEPAGE);
             }
 
             @Override
@@ -757,6 +765,7 @@
             @Override
             public void onOverviewModeFinishedHiding() {
                 mToolbar.onTabSwitcherTransitionFinished();
+                updateButtonStatus();
             }
         };
 
@@ -1880,8 +1889,12 @@
         if (mToolbar.getMenuButtonWrapper() != null && !isBottomToolbarVisible()) {
             mToolbar.getMenuButtonWrapper().setVisibility(View.VISIBLE);
         }
+
+        // TODO(crbug.com/1041475): Separate enabling the IdentityDiscController from enabling the
+        // ExperimentalButton.
         mIdentityDiscController.updateButtonState(
-                mLocationBarModel.getNewTabPageForCurrentTab() != null);
+                mLocationBarModel.getNewTabPageForCurrentTab() != null
+                || mOverviewModeState == OverviewModeState.SHOWN_HOMEPAGE);
     }
 
     private void updateBookmarkButtonStatus() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarCoordinator.java
index 41154771..31ad72d3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarCoordinator.java
@@ -4,9 +4,12 @@
 
 package org.chromium.chrome.browser.toolbar.top;
 
+import android.graphics.drawable.Drawable;
 import android.view.View;
 import android.view.ViewStub;
 
+import androidx.annotation.StringRes;
+
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
 import org.chromium.chrome.browser.incognito.IncognitoUtils;
@@ -113,6 +116,43 @@
         mToolbarMediator.setOverviewModeBehavior(overviewModeBehavior);
     }
 
+    /**
+     * Enable the experimental toolbar button.
+     * @param onClickListener The {@link OnClickListener} to be called when the button is clicked.
+     * @param image The drawable to display for the button.
+     * @param contentDescriptionResId The resource id of the content description for the button.
+     */
+    void enableExperimentalButton(View.OnClickListener onClickListener, Drawable image,
+            @StringRes int contentDescriptionResId) {
+        mToolbarMediator.enableIdentityDisc(onClickListener, image, contentDescriptionResId);
+    }
+
+    /**
+     * Updates image displayed on experimental button.
+     * @param image The new image for the button.
+     */
+    void updateExperimentalButtonImage(Drawable image) {
+        mToolbarMediator.updateIdentityDiscImage(image);
+    }
+
+    /**
+     * Disable the experimental toolbar button.
+     */
+    void disableExperimentalButton() {
+        mToolbarMediator.disableIdentityDisc();
+    }
+
+    /**
+     * Displays in-product help for experimental button.
+     * @param stringId The id of the string resource for the text that should be shown.
+     * @param accessibilityStringId The id of the string resource of the accessibility text.
+     * @param dismissedCallback The callback that will be called when in-product help is dismissed.
+     */
+    void showIPHOnExperimentalButton(@StringRes int stringId, @StringRes int accessibilityStringId,
+            Runnable dismissedCallback) {
+        mToolbarMediator.showIPHOnIdentityDisc(stringId, accessibilityStringId, dismissedCallback);
+    }
+
     void onNativeLibraryReady() {
         mToolbarMediator.onNativeLibraryReady();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java
index 700e09a..003f273 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarMediator.java
@@ -7,6 +7,11 @@
 import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.ACCESSIBILITY_ENABLED;
 import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.APP_MENU_BUTTON_HELPER;
 import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.BUTTONS_CLICKABLE;
+import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.IDENTITY_DISC_CLICK_HANDLER;
+import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.IDENTITY_DISC_DESCRIPTION;
+import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.IDENTITY_DISC_IMAGE;
+import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.IDENTITY_DISC_IPH;
+import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.IDENTITY_DISC_IS_VISIBLE;
 import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.INCOGNITO_STATE_PROVIDER;
 import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.IS_INCOGNITO;
 import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.IS_VISIBLE;
@@ -15,8 +20,11 @@
 import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.NEW_TAB_BUTTON_IS_VISIBLE;
 import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.NEW_TAB_CLICK_HANDLER;
 
+import android.graphics.drawable.Drawable;
 import android.view.View;
 
+import androidx.annotation.StringRes;
+
 import org.chromium.chrome.browser.compositor.layouts.EmptyOverviewModeObserver;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior;
 import org.chromium.chrome.browser.compositor.layouts.OverviewModeBehavior.OverviewModeObserver;
@@ -27,6 +35,7 @@
 import org.chromium.chrome.browser.tabmodel.TabModelSelector;
 import org.chromium.chrome.browser.tabmodel.TabModelSelectorObserver;
 import org.chromium.chrome.browser.toolbar.IncognitoStateProvider;
+import org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.IPHContainer;
 import org.chromium.chrome.browser.ui.appmenu.AppMenuButtonHelper;
 import org.chromium.chrome.browser.util.AccessibilityUtil;
 import org.chromium.components.search_engines.TemplateUrlService.TemplateUrlServiceObserver;
@@ -43,6 +52,7 @@
     @OverviewModeState
     private int mOverviewModeState;
     private boolean mIsGoogleSearchEngine;
+    private boolean mEnableIdentityDisc;
 
     StartSurfaceToolbarMediator(PropertyModel model) {
         mPropertyModel = model;
@@ -93,10 +103,12 @@
                 @Override
                 public void onTabModelSelected(TabModel newModel, TabModel oldModel) {
                     mPropertyModel.set(IS_INCOGNITO, mTabModelSelector.isIncognitoSelected());
+                    updateIdentityDiscVisibility();
                 }
             };
         }
         mPropertyModel.set(IS_INCOGNITO, mTabModelSelector.isIncognitoSelected());
+        updateIdentityDiscVisibility();
         mTabModelSelector.addObserver(mTabModelSelectorObserver);
     }
 
@@ -131,6 +143,7 @@
                     mOverviewModeState = overviewModeState;
                     updateNewTabButtonVisibility();
                     updateLogoVisibility(mIsGoogleSearchEngine);
+                    updateIdentityDiscVisibility();
                 }
                 @Override
                 public void onOverviewModeFinishedShowing() {
@@ -156,6 +169,35 @@
         mPropertyModel.set(LOGO_IS_VISIBLE, shouldShowLogo);
     }
 
+    void enableIdentityDisc(View.OnClickListener onClickListener, Drawable image,
+            @StringRes int contentDescriptionResId) {
+        mEnableIdentityDisc = true;
+        mPropertyModel.set(IDENTITY_DISC_CLICK_HANDLER, onClickListener);
+        mPropertyModel.set(IDENTITY_DISC_IMAGE, image);
+        mPropertyModel.set(IDENTITY_DISC_DESCRIPTION, contentDescriptionResId);
+        updateIdentityDiscVisibility();
+    }
+
+    void updateIdentityDiscImage(Drawable image) {
+        mPropertyModel.set(IDENTITY_DISC_IMAGE, image);
+    }
+
+    void disableIdentityDisc() {
+        mEnableIdentityDisc = false;
+        mPropertyModel.set(IDENTITY_DISC_IS_VISIBLE, false);
+    }
+
+    void showIPHOnIdentityDisc(@StringRes int stringId, @StringRes int accessibilityStringId,
+            Runnable dismissedCallback) {
+        // Only show IPH if IdentityDisc is actually visible, otherwise dismiss.
+        if (mPropertyModel.get(IDENTITY_DISC_IS_VISIBLE)) {
+            mPropertyModel.set(IDENTITY_DISC_IPH,
+                    new IPHContainer(stringId, accessibilityStringId, dismissedCallback));
+        } else if (dismissedCallback != null) {
+            dismissedCallback.run();
+        }
+    }
+
     private void updateNewTabButtonVisibility() {
         // This toolbar is only shown for tab switcher when accessibility is enabled. Note that
         // OverviewListLayout will be shown as the tab switcher instead of the star surface.
@@ -164,4 +206,10 @@
                 || AccessibilityUtil.isAccessibilityEnabled();
         mPropertyModel.set(NEW_TAB_BUTTON_IS_VISIBLE, isShownTabswitcherState);
     }
+
+    private void updateIdentityDiscVisibility() {
+        mPropertyModel.set(IDENTITY_DISC_IS_VISIBLE,
+                mOverviewModeState == OverviewModeState.SHOWN_HOMEPAGE && mEnableIdentityDisc
+                        && !mTabModelSelector.isIncognitoSelected());
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarProperties.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarProperties.java
index f0e98d9..5910af2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarProperties.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarProperties.java
@@ -4,8 +4,11 @@
 
 package org.chromium.chrome.browser.toolbar.top;
 
+import android.graphics.drawable.Drawable;
 import android.view.View;
 
+import androidx.annotation.StringRes;
+
 import org.chromium.chrome.browser.toolbar.IncognitoStateProvider;
 import org.chromium.chrome.browser.ui.appmenu.AppMenuButtonHelper;
 import org.chromium.ui.modelutil.PropertyKey;
@@ -13,6 +16,21 @@
 
 /** List of the start surface toolbar properties. */
 class StartSurfaceToolbarProperties {
+    public static class IPHContainer {
+        @StringRes
+        public final int stringId;
+        @StringRes
+        public final int accessibilityStringId;
+        public Runnable dismissedCallback;
+
+        IPHContainer(@StringRes int stringId, @StringRes int accessibilityStringId,
+                Runnable dismissedCallback) {
+            this.stringId = stringId;
+            this.accessibilityStringId = accessibilityStringId;
+            this.dismissedCallback = dismissedCallback;
+        }
+    }
+
     private StartSurfaceToolbarProperties() {}
 
     public static final PropertyModel
@@ -24,6 +42,17 @@
     public static final PropertyModel
             .WritableObjectPropertyKey<View.OnClickListener> NEW_TAB_CLICK_HANDLER =
             new PropertyModel.WritableObjectPropertyKey<View.OnClickListener>();
+    public static final PropertyModel
+            .WritableObjectPropertyKey<View.OnClickListener> IDENTITY_DISC_CLICK_HANDLER =
+            new PropertyModel.WritableObjectPropertyKey<View.OnClickListener>();
+    public static final PropertyModel.WritableObjectPropertyKey<Drawable> IDENTITY_DISC_IMAGE =
+            new PropertyModel.WritableObjectPropertyKey<Drawable>();
+    public static final PropertyModel.WritableIntPropertyKey IDENTITY_DISC_DESCRIPTION =
+            new PropertyModel.WritableIntPropertyKey();
+    public static final PropertyModel.WritableObjectPropertyKey<IPHContainer> IDENTITY_DISC_IPH =
+            new PropertyModel.WritableObjectPropertyKey<IPHContainer>();
+    public static final PropertyModel.WritableBooleanPropertyKey IDENTITY_DISC_IS_VISIBLE =
+            new PropertyModel.WritableBooleanPropertyKey();
     public static final PropertyModel.WritableBooleanPropertyKey IS_VISIBLE =
             new PropertyModel.WritableBooleanPropertyKey();
     public static final PropertyModel.WritableBooleanPropertyKey LOGO_IS_VISIBLE =
@@ -42,5 +71,7 @@
     public static final PropertyKey[] ALL_KEYS =
             new PropertyKey[] {APP_MENU_BUTTON_HELPER, NEW_TAB_CLICK_HANDLER, IS_VISIBLE,
                     LOGO_IS_VISIBLE, IS_INCOGNITO, INCOGNITO_STATE_PROVIDER, ACCESSIBILITY_ENABLED,
-                    MENU_IS_VISIBLE, NEW_TAB_BUTTON_IS_VISIBLE, BUTTONS_CLICKABLE};
+                    MENU_IS_VISIBLE, NEW_TAB_BUTTON_IS_VISIBLE, BUTTONS_CLICKABLE,
+                    IDENTITY_DISC_IS_VISIBLE, IDENTITY_DISC_CLICK_HANDLER, IDENTITY_DISC_IMAGE,
+                    IDENTITY_DISC_DESCRIPTION, IDENTITY_DISC_IPH};
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarView.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarView.java
index 6cd5a00..d8f75c43 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarView.java
@@ -7,17 +7,24 @@
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.support.v7.content.res.AppCompatResources;
 import android.util.AttributeSet;
 import android.view.View;
+import android.widget.ImageButton;
 import android.widget.RelativeLayout;
 
+import androidx.annotation.Nullable;
+import androidx.annotation.StringRes;
+
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.toolbar.IncognitoStateProvider;
 import org.chromium.chrome.browser.toolbar.MenuButton;
 import org.chromium.chrome.browser.toolbar.NewTabButton;
+import org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.IPHContainer;
 import org.chromium.chrome.browser.ui.appmenu.AppMenuButtonHelper;
+import org.chromium.chrome.browser.ui.widget.textbubble.TextBubble;
 import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.components.browser_ui.styles.ChromeColors;
 
@@ -27,6 +34,8 @@
     private View mIncognitoSwitch;
     private MenuButton mMenuButton;
     private View mLogo;
+    @Nullable
+    private ImageButton mIdentityDiscButton;
     private int mPrimaryColor;
     private ColorStateList mLightIconTint;
     private ColorStateList mDarkIconTint;
@@ -46,6 +55,13 @@
         mIncognitoSwitch = findViewById(R.id.incognito_switch);
         mMenuButton = findViewById(R.id.menu_button_wrapper);
         mLogo = findViewById(R.id.logo);
+        mIdentityDiscButton = findViewById(R.id.experimental_toolbar_button_start);
+
+        // Change padding in layout file programmatically, since padding in layout file can not be
+        // changed in ViewStub.
+        final int buttonPadding = getContext().getResources().getDimensionPixelOffset(
+                R.dimen.start_surface_toolbar_button_padding_to_button);
+        mIdentityDiscButton.setPadding(buttonPadding, 0, buttonPadding, 0);
         updatePrimaryColorAndTint(false);
     }
 
@@ -100,6 +116,14 @@
      */
     void setMenuButtonVisibility(boolean isVisible) {
         mMenuButton.setVisibility(isVisible ? View.VISIBLE : View.GONE);
+        final int buttonPaddingLeft = getContext().getResources().getDimensionPixelOffset(
+                R.dimen.start_surface_toolbar_button_padding_to_button);
+        final int buttonPaddingRight =
+                (isVisible ? buttonPaddingLeft
+                           : getContext().getResources().getDimensionPixelOffset(
+                                   R.dimen.start_surface_toolbar_button_padding_to_edge));
+        mIdentityDiscButton.setPadding(buttonPaddingLeft, 0, buttonPaddingRight, 0);
+        mNewTabButton.setPadding(buttonPaddingLeft, 0, buttonPaddingRight, 0);
     }
 
     /**
@@ -135,6 +159,52 @@
         mNewTabButton.onAccessibilityStatusChanged();
     }
 
+    /**
+     * @param isVisible Whether the identity disc is visible.
+     */
+    void setIdentityDiscVisibility(boolean isVisible) {
+        mIdentityDiscButton.setVisibility(isVisible ? View.VISIBLE : View.GONE);
+    }
+
+    /**
+     * Sets the {@link OnClickListener} that will be notified when the identity disc button is
+     * pressed.
+     * @param listener The callback that will be notified when the identity disc  is pressed.
+     */
+    void setIdentityDiscClickHandler(View.OnClickListener listener) {
+        mIdentityDiscButton.setOnClickListener(listener);
+    }
+
+    /**
+     * Updates the image displayed on the identity disc button.
+     * @param image The new image for the button.
+     */
+    void setIdentityDiscImage(Drawable image) {
+        mIdentityDiscButton.setImageDrawable(image);
+    }
+
+    /**
+     * Updates idnetity disc content description.
+     * @param contentDescriptionResId The new description for the button.
+     */
+    void setIdentityDiscContentDescription(@StringRes int contentDescriptionResId) {
+        mIdentityDiscButton.setContentDescription(
+                getContext().getResources().getString(contentDescriptionResId));
+    }
+
+    /**
+     * Show the IPH for the identity disc button.
+     */
+    void showIPHOnIdentityDisc(IPHContainer iphContainer) {
+        TextBubble textBubble = new TextBubble(getContext(), mIdentityDiscButton,
+                iphContainer.stringId, iphContainer.accessibilityStringId, mIdentityDiscButton);
+        textBubble.setDismissOnTouchInteraction(true);
+        if (iphContainer.dismissedCallback != null) {
+            textBubble.addOnDismissListener(() -> { iphContainer.dismissedCallback.run(); });
+        }
+        textBubble.show();
+    }
+
     private void updatePrimaryColorAndTint(boolean isIncognito) {
         int primaryColor = ChromeColors.getPrimaryBackgroundColor(getResources(), isIncognito);
         setBackgroundColor(primaryColor);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarViewBinder.java
index 5cf9299..9928553 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/StartSurfaceToolbarViewBinder.java
@@ -7,6 +7,11 @@
 import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.ACCESSIBILITY_ENABLED;
 import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.APP_MENU_BUTTON_HELPER;
 import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.BUTTONS_CLICKABLE;
+import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.IDENTITY_DISC_CLICK_HANDLER;
+import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.IDENTITY_DISC_DESCRIPTION;
+import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.IDENTITY_DISC_IMAGE;
+import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.IDENTITY_DISC_IPH;
+import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.IDENTITY_DISC_IS_VISIBLE;
 import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.INCOGNITO_STATE_PROVIDER;
 import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.IS_INCOGNITO;
 import static org.chromium.chrome.browser.toolbar.top.StartSurfaceToolbarProperties.IS_VISIBLE;
@@ -24,24 +29,34 @@
 class StartSurfaceToolbarViewBinder {
     public static void bind(
             PropertyModel model, StartSurfaceToolbarView view, PropertyKey propertyKey) {
-        if (propertyKey == APP_MENU_BUTTON_HELPER) {
+        if (propertyKey == ACCESSIBILITY_ENABLED) {
+            view.onAccessibilityStatusChanged(model.get(ACCESSIBILITY_ENABLED));
+        } else if (propertyKey == APP_MENU_BUTTON_HELPER) {
             view.setAppMenuButtonHelper(model.get(APP_MENU_BUTTON_HELPER));
         } else if (propertyKey == BUTTONS_CLICKABLE) {
             view.setButtonClickableState(model.get(BUTTONS_CLICKABLE));
-        } else if (propertyKey == NEW_TAB_CLICK_HANDLER) {
-            view.setOnNewTabClickHandler(model.get(NEW_TAB_CLICK_HANDLER));
+        } else if (propertyKey == IDENTITY_DISC_CLICK_HANDLER) {
+            view.setIdentityDiscClickHandler(model.get(IDENTITY_DISC_CLICK_HANDLER));
+        } else if (propertyKey == IDENTITY_DISC_DESCRIPTION) {
+            view.setIdentityDiscContentDescription(model.get(IDENTITY_DISC_DESCRIPTION));
+        } else if (propertyKey == IDENTITY_DISC_IMAGE) {
+            view.setIdentityDiscImage(model.get(IDENTITY_DISC_IMAGE));
+        } else if (propertyKey == IDENTITY_DISC_IPH) {
+            view.showIPHOnIdentityDisc(model.get(IDENTITY_DISC_IPH));
+        } else if (propertyKey == IDENTITY_DISC_IS_VISIBLE) {
+            view.setIdentityDiscVisibility(model.get(IDENTITY_DISC_IS_VISIBLE));
+        } else if (propertyKey == INCOGNITO_STATE_PROVIDER) {
+            view.setIncognitoStateProvider(model.get(INCOGNITO_STATE_PROVIDER));
+        } else if (propertyKey == IS_INCOGNITO) {
+            view.updateIncognito(model.get(IS_INCOGNITO));
         } else if (propertyKey == IS_VISIBLE) {
             view.setVisibility(model.get(IS_VISIBLE) ? View.VISIBLE : View.GONE);
         } else if (propertyKey == LOGO_IS_VISIBLE) {
             view.setLogoVisibility(model.get(LOGO_IS_VISIBLE));
-        } else if (propertyKey == IS_INCOGNITO) {
-            view.updateIncognito(model.get(IS_INCOGNITO));
-        } else if (propertyKey == INCOGNITO_STATE_PROVIDER) {
-            view.setIncognitoStateProvider(model.get(INCOGNITO_STATE_PROVIDER));
-        } else if (propertyKey == ACCESSIBILITY_ENABLED) {
-            view.onAccessibilityStatusChanged(model.get(ACCESSIBILITY_ENABLED));
         } else if (propertyKey == MENU_IS_VISIBLE) {
             view.setMenuButtonVisibility(model.get(MENU_IS_VISIBLE));
+        } else if (propertyKey == NEW_TAB_CLICK_HANDLER) {
+            view.setOnNewTabClickHandler(model.get(NEW_TAB_CLICK_HANDLER));
         } else if (propertyKey == NEW_TAB_BUTTON_IS_VISIBLE) {
             view.setNewTabButtonVisibility(model.get(NEW_TAB_BUTTON_IS_VISIBLE));
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
index 899c7d9..cf59c43 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/top/TopToolbarCoordinator.java
@@ -625,6 +625,10 @@
      */
     public void enableExperimentalButton(View.OnClickListener onClickListener, Drawable image,
             @StringRes int contentDescriptionResId) {
+        if (FeatureUtilities.isStartSurfaceSinglePaneEnabled()) {
+            mStartSurfaceToolbarCoordinator.enableExperimentalButton(
+                    onClickListener, image, contentDescriptionResId);
+        }
         mToolbarLayout.enableExperimentalButton(onClickListener, image, contentDescriptionResId);
     }
 
@@ -644,6 +648,9 @@
      * @return The experimental toolbar button if it exists.
      */
     public void updateExperimentalButtonImage(Drawable image) {
+        if (FeatureUtilities.isStartSurfaceSinglePaneEnabled()) {
+            mStartSurfaceToolbarCoordinator.updateExperimentalButtonImage(image);
+        }
         mToolbarLayout.updateExperimentalButtonImage(image);
     }
 
@@ -651,6 +658,9 @@
      * Disable the experimental toolbar button.
      */
     public void disableExperimentalButton() {
+        if (FeatureUtilities.isStartSurfaceSinglePaneEnabled()) {
+            mStartSurfaceToolbarCoordinator.disableExperimentalButton();
+        }
         mToolbarLayout.disableExperimentalButton();
     }
 
@@ -662,6 +672,12 @@
      */
     public void showIPHOnExperimentalButton(@StringRes int stringId,
             @StringRes int accessibilityStringId, Runnable dismissedCallback) {
+        if (mStartSurfaceToolbarCoordinator != null
+                && mToolbarLayout.getToolbarDataProvider().isInOverviewAndShowingOmnibox()) {
+            mStartSurfaceToolbarCoordinator.showIPHOnExperimentalButton(
+                    stringId, accessibilityStringId, dismissedCallback);
+            return;
+        }
         mToolbarLayout.showIPHOnExperimentalButton(
                 stringId, accessibilityStringId, dismissedCallback);
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArImmersiveOverlay.java b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArImmersiveOverlay.java
index cf153b8..4a1b9c3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/vr/ArImmersiveOverlay.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/vr/ArImmersiveOverlay.java
@@ -28,6 +28,7 @@
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.content_public.browser.ScreenOrientationDelegate;
 import org.chromium.content_public.browser.ScreenOrientationProvider;
+import org.chromium.ui.display.DisplayAndroidManager;
 import org.chromium.ui.widget.Toast;
 
 /**
@@ -234,8 +235,9 @@
         // transport even if the currently-visible part in the surface view is smaller than this. We
         // shouldn't get resize events since we're using FLAG_LAYOUT_STABLE and are locking screen
         // orientation.
+        Display display = DisplayAndroidManager.getDefaultDisplayForContext(mActivity);
         if (mSurfaceReportedReady) {
-            int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
+            int rotation = display.getRotation();
             if (DEBUG_LOGS) {
                 Log.i(TAG,
                         "surfaceChanged ignoring change to width=" + width + " height=" + height
@@ -268,7 +270,6 @@
         // after the session starts, but the session doesn't start until we report the drawing
         // surface being ready (including a configured size), so we use this reported size assuming
         // that's what the fullscreen mode will use.
-        Display display = mActivity.getWindowManager().getDefaultDisplay();
         Point size = new Point();
         display.getRealSize(size);
 
@@ -282,7 +283,7 @@
             height = size.y;
         }
 
-        int rotation = mActivity.getWindowManager().getDefaultDisplay().getRotation();
+        int rotation = display.getRotation();
         if (DEBUG_LOGS) {
             Log.i(TAG, "surfaceChanged size=" + width + "x" + height + " rotation=" + rotation);
         }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabTest.java
index afe0407d..6fc7990 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabTest.java
@@ -21,14 +21,12 @@
 import org.chromium.chrome.browser.tab.EmptyTabObserver;
 import org.chromium.chrome.browser.tab.SadTab;
 import org.chromium.chrome.browser.tab.Tab;
-import org.chromium.chrome.browser.tab.TabImpl;
 import org.chromium.chrome.browser.tab.TabObserver;
 import org.chromium.chrome.browser.tab.TabSelectionType;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.util.ApplicationTestUtils;
 import org.chromium.chrome.test.util.ChromeTabUtils;
-import org.chromium.components.security_state.ConnectionSecurityLevel;
 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.TestThreadUtils;
@@ -136,13 +134,4 @@
         Assert.assertFalse(mTab.needsReload());
         Assert.assertFalse(isShowingSadTab());
     }
-
-    @Test
-    @SmallTest
-    @Feature({"Tab"})
-    public void testTabSecurityLevel() {
-        TestThreadUtils.runOnUiThreadBlocking(() -> {
-            Assert.assertEquals(ConnectionSecurityLevel.NONE, ((TabImpl) mTab).getSecurityLevel());
-        });
-    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarIntegrationTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarIntegrationTest.java
index b2c25de6..1b2a7b6 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarIntegrationTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/UrlBarIntegrationTest.java
@@ -157,7 +157,7 @@
     @Test
     @SmallTest
     @Feature({"Omnibox"})
-    // TODO(crbug.com/1048469): Investigate and enable this test for the search engine logo feature.
+    // TODO(crbug.com/1028469): Investigate and enable this test for the search engine logo feature.
     @DisableFeatures("OmniboxSearchEngineLogo")
     @RetryOnFailure
     public void testLongPress() {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/settings/website/CookieControlsBridgeTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/settings/website/CookieControlsBridgeTest.java
new file mode 100644
index 0000000..37cb1cf98
--- /dev/null
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/settings/website/CookieControlsBridgeTest.java
@@ -0,0 +1,233 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.settings.website;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import org.chromium.base.test.util.CallbackHelper;
+import org.chromium.base.test.util.CommandLineFlags;
+import org.chromium.base.test.util.RetryOnFailure;
+import org.chromium.chrome.browser.ChromeActivity;
+import org.chromium.chrome.browser.ChromeSwitches;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
+import org.chromium.chrome.browser.preferences.Pref;
+import org.chromium.chrome.browser.preferences.PrefServiceBridge;
+import org.chromium.chrome.browser.tab.Tab;
+import org.chromium.chrome.test.ChromeActivityTestRule;
+import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.util.browser.Features.EnableFeatures;
+import org.chromium.components.content_settings.ContentSettingsType;
+import org.chromium.components.content_settings.CookieControlsMode;
+import org.chromium.content_public.browser.test.util.JavaScriptUtils;
+import org.chromium.content_public.browser.test.util.TestThreadUtils;
+import org.chromium.net.test.EmbeddedTestServer;
+
+/**
+ * Integration tests for CookieControlsBridge.
+ */
+@RunWith(ChromeJUnit4ClassRunner.class)
+@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
+@EnableFeatures(ChromeFeatureList.IMPROVED_COOKIE_CONTROLS)
+public class CookieControlsBridgeTest {
+    private class TestCallbackHandler implements CookieControlsBridge.CookieControlsView {
+        private CallbackHelper mHelper;
+
+        public TestCallbackHandler(CallbackHelper helper) {
+            mHelper = helper;
+        }
+
+        @Override
+        public void onCookieBlockingStatusChanged(@CookieControlsControllerStatus int status) {
+            mStatus = status;
+            mHelper.notifyCalled();
+        }
+
+        @Override
+        public void onBlockedCookiesCountChanged(int blockedCookies) {
+            mBlockedCookies = blockedCookies;
+            mHelper.notifyCalled();
+        }
+    }
+
+    @Rule
+    public ChromeActivityTestRule<ChromeActivity> mActivityTestRule =
+            new ChromeActivityTestRule<>(ChromeActivity.class);
+    private EmbeddedTestServer mTestServer;
+    private CallbackHelper mCallbackHelper;
+    private TestCallbackHandler mCallbackHandler;
+    private CookieControlsBridge mCookieControlsBridge;
+    private int mStatus;
+    private int mBlockedCookies;
+
+    @Before
+    public void setUp() throws Exception {
+        mCallbackHelper = new CallbackHelper();
+        mCallbackHandler = new TestCallbackHandler(mCallbackHelper);
+        mActivityTestRule.startMainActivityOnBlankPage();
+        mTestServer = EmbeddedTestServer.createAndStartServer(InstrumentationRegistry.getContext());
+        mStatus = CookieControlsControllerStatus.UNINITIALIZED;
+        mBlockedCookies = -1;
+    }
+
+    @After
+    public void tearDown() {
+        mTestServer.stopAndDestroyServer();
+    }
+
+    /**
+     * Test two callbacks (one for status disabled, one for blocked cookies count) if cookie
+     * controls is off.
+     */
+    @Test
+    @SmallTest
+    @RetryOnFailure
+    public void testCookieBridgeWithTPCookiesDisabled() throws Exception {
+        int expectedCookiesToBlock = 0;
+        int expectedStatus = CookieControlsControllerStatus.DISABLED;
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            // Set CookieControlsMode Pref to Off
+            PrefServiceBridge.getInstance().setInteger(
+                    Pref.COOKIE_CONTROLS_MODE, CookieControlsMode.OFF);
+        });
+        int currentCallCount = mCallbackHelper.getCallCount();
+
+        // Navigate to a page
+        final String url = mTestServer.getURL("/chrome/test/data/android/cookie.html");
+        Tab tab = mActivityTestRule.loadUrlInNewTab(url, false);
+
+        // Create cookie bridge and wait for desired callbacks.
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mCookieControlsBridge =
+                    new CookieControlsBridge(mCallbackHandler, tab.getWebContents());
+        });
+
+        mCallbackHelper.waitForCallback(currentCallCount, 2);
+        Assert.assertEquals(expectedStatus, mStatus);
+        Assert.assertEquals(expectedCookiesToBlock, mBlockedCookies);
+    }
+
+    /**
+     * Test two callbacks (one for status enabled, one for blocked cookies count) if cookie controls
+     * is on. No cookies trying to be set.
+     */
+    @Test
+    @SmallTest
+    @RetryOnFailure
+    public void testCookieBridgeWith3PCookiesEnabled() throws Exception {
+        int expectedCookiesToBlock = 0;
+        int expectedStatus = CookieControlsControllerStatus.ENABLED;
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            // Set CookieControlsMode Pref to On
+            PrefServiceBridge.getInstance().setInteger(
+                    Pref.COOKIE_CONTROLS_MODE, CookieControlsMode.ON);
+        });
+        int currentCallCount = mCallbackHelper.getCallCount();
+
+        // Navigate to a page
+        final String url = mTestServer.getURL("/chrome/test/data/android/cookie.html");
+        Tab tab = mActivityTestRule.loadUrlInNewTab(url, false);
+
+        // Create cookie bridge and wait for desired callbacks.
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mCookieControlsBridge =
+                    new CookieControlsBridge(mCallbackHandler, tab.getWebContents());
+        });
+
+        mCallbackHelper.waitForCallback(currentCallCount, 2);
+        Assert.assertEquals(expectedStatus, mStatus);
+        Assert.assertEquals(expectedCookiesToBlock, mBlockedCookies);
+    }
+
+    /**
+     * Test blocked cookies count changes when new cookie tries to be set. Only one callback because
+     * status remains enabled.
+     */
+    @Test
+    @SmallTest
+    @RetryOnFailure
+    public void testCookieBridgeWithChangingBlockedCookiesCount() throws Exception {
+        int expectedCookiesToBlock = 0;
+        int expectedStatus = CookieControlsControllerStatus.ENABLED;
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            // Set CookieControlsMode Pref to On
+            PrefServiceBridge.getInstance().setInteger(
+                    Pref.COOKIE_CONTROLS_MODE, CookieControlsMode.ON);
+            // Block all cookies
+            WebsitePreferenceBridge.setCategoryEnabled(ContentSettingsType.COOKIES, false);
+        });
+        int currentCallCount = mCallbackHelper.getCallCount();
+
+        // Navigate to a page
+        final String url = mTestServer.getURL("/chrome/test/data/android/cookie.html");
+        Tab tab = mActivityTestRule.loadUrlInNewTab(url, false);
+
+        // Create cookie bridge and wait for desired callbacks.
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mCookieControlsBridge =
+                    new CookieControlsBridge(mCallbackHandler, tab.getWebContents());
+        });
+
+        mCallbackHelper.waitForCallback(currentCallCount, 2);
+        Assert.assertEquals(expectedStatus, mStatus);
+        Assert.assertEquals(expectedCookiesToBlock, mBlockedCookies);
+
+        // Try to set a cookie on the page when cookies are blocked.
+        currentCallCount = mCallbackHelper.getCallCount();
+        expectedCookiesToBlock = 1;
+        JavaScriptUtils.executeJavaScriptAndWaitForResult(tab.getWebContents(), "setCookie()");
+        mCallbackHelper.waitForCallback(currentCallCount, 1);
+        Assert.assertEquals(expectedCookiesToBlock, mBlockedCookies);
+    }
+
+    /**
+     * Test blocked cookies works with CookieControlsMode.INCOGNITO_ONLY.
+     */
+    @Test
+    @SmallTest
+    @RetryOnFailure
+    public void testCookieBridgeWithIncognitoSetting() throws Exception {
+        int expectedCookiesToBlock = 0;
+        int expectedStatus = CookieControlsControllerStatus.DISABLED;
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            // Set CookieControlsMode Pref to IncognitoOnly
+            PrefServiceBridge.getInstance().setInteger(
+                    Pref.COOKIE_CONTROLS_MODE, CookieControlsMode.INCOGNITO_ONLY);
+        });
+        int currentCallCount = mCallbackHelper.getCallCount();
+
+        // Navigate to a normal page
+        final String url = mTestServer.getURL("/chrome/test/data/android/cookie.html");
+        Tab tab = mActivityTestRule.loadUrlInNewTab(url, false);
+
+        // Create cookie bridge and wait for desired callbacks.
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mCookieControlsBridge =
+                    new CookieControlsBridge(mCallbackHandler, tab.getWebContents());
+        });
+
+        mCallbackHelper.waitForCallback(currentCallCount, 2);
+        Assert.assertEquals(expectedStatus, mStatus);
+        Assert.assertEquals(expectedCookiesToBlock, mBlockedCookies);
+
+        // Make new incognito page now
+        expectedStatus = CookieControlsControllerStatus.ENABLED;
+        Tab incognitoTab = mActivityTestRule.loadUrlInNewTab(url, true);
+        TestThreadUtils.runOnUiThreadBlocking(() -> {
+            mCookieControlsBridge =
+                    new CookieControlsBridge(mCallbackHandler, incognitoTab.getWebContents());
+        });
+        mCallbackHelper.waitForCallback(currentCallCount, 2);
+        Assert.assertEquals(expectedStatus, mStatus);
+        Assert.assertEquals(expectedCookiesToBlock, mBlockedCookies);
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java
index b9c3996..4b2f9b2 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/vr/VrBrowserTransitionTest.java
@@ -394,7 +394,7 @@
         VrShellDelegateUtils.getDelegateInstance().overrideDaydreamApiForTesting(mockApiWithDoff);
 
         TestThreadUtils.runOnUiThreadBlocking(() -> {
-            SettingsLauncher.getInstance().launchSettingsPage(context, null);
+            SettingsLauncher.getInstance().launchSettingsPage(context);
             VrShellDelegateUtils.getDelegateInstance().acceptDoffPromptForTesting();
         });
         CriteriaHelper.pollUiThread(() -> {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityBrowserControlsVisibilityManagerTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityBrowserControlsVisibilityManagerTest.java
index f38de87..d2cc41d 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityBrowserControlsVisibilityManagerTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/browserservices/trustedwebactivityui/controller/TrustedWebActivityBrowserControlsVisibilityManagerTest.java
@@ -7,8 +7,11 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.any;
 import static org.mockito.Mockito.atLeast;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
@@ -50,6 +53,7 @@
     @Mock
     public CloseButtonVisibilityManager mCloseButtonVisibilityManager;
 
+    @Mock
     TrustedWebActivityBrowserControlsVisibilityManager mController;
 
     @Before
@@ -65,9 +69,8 @@
      */
     @Test
     public void testDangerousSecurityLevel() {
-        setTabSecurityLevel(ConnectionSecurityLevel.DANGEROUS);
-
         mController = buildController(mock(BrowserServicesIntentDataProvider.class));
+        setTabSecurityLevel(ConnectionSecurityLevel.DANGEROUS);
         mController.updateIsInTwaMode(true);
         assertEquals(BrowserControlsState.SHOWN, getLastBrowserControlsState());
         assertFalse(getLastCloseButtonVisibility());
@@ -131,7 +134,7 @@
     }
 
     private void setTabSecurityLevel(int securityLevel) {
-        when(mTab.getSecurityLevel()).thenReturn(securityLevel);
+        doReturn(securityLevel).when(mController).getSecurityLevel(any());
     }
 
     private BrowserServicesIntentDataProvider buildWebApkIntentDataProvider(
@@ -144,9 +147,9 @@
 
     private TrustedWebActivityBrowserControlsVisibilityManager buildController(
             BrowserServicesIntentDataProvider intentDataProvider) {
-        return new TrustedWebActivityBrowserControlsVisibilityManager(mTabObserverRegistrar,
+        return spy(new TrustedWebActivityBrowserControlsVisibilityManager(mTabObserverRegistrar,
                 mTabProvider, mToolbarCoordinator, mCloseButtonVisibilityManager,
-                intentDataProvider);
+                intentDataProvider));
     }
 
     /**
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabStatusBarColorProviderTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabStatusBarColorProviderTest.java
index 76eb697..26a097e 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabStatusBarColorProviderTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/customtabs/CustomTabStatusBarColorProviderTest.java
@@ -4,6 +4,8 @@
 
 package org.chromium.chrome.browser.customtabs;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -16,6 +18,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.annotation.Config;
 
@@ -44,12 +47,12 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        mColorProvider = new CustomTabStatusBarColorProvider(
-                mCustomTabIntentDataProvider, mStatusBarColorController);
+        mColorProvider = Mockito.spy(new CustomTabStatusBarColorProvider(
+                mCustomTabIntentDataProvider, mStatusBarColorController));
 
         when(mCustomTabIntentDataProvider.getToolbarColor()).thenReturn(USER_PROVIDED_COLOR);
         when(mCustomTabIntentDataProvider.hasCustomToolbarColor()).thenReturn(true);
-        when(mTab.isPreview()).thenReturn(false);
+        doReturn(false).when(mColorProvider).isPreview(any());
     }
 
     @Test
@@ -77,7 +80,7 @@
 
     @Test
     public void useTabThemeColor_preview() {
-        when(mTab.isPreview()).thenReturn(true);
+        doReturn(true).when(mColorProvider).isPreview(any());
         mColorProvider.setUseTabThemeColor(true);
 
         Assert.assertEquals(DEFAULT_STATUS_BAR_COLOR, getStatusBarColor(mTab));
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/ToSAckedReceiverTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/ToSAckedReceiverTest.java
index 5d472ca3..9b4c67f 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/ToSAckedReceiverTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/firstrun/ToSAckedReceiverTest.java
@@ -18,8 +18,9 @@
 import org.robolectric.annotation.Config;
 import org.robolectric.util.ReflectionHelpers;
 
-import org.chromium.base.ContextUtils;
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.chrome.browser.preferences.ChromePreferenceKeys;
+import org.chromium.chrome.browser.preferences.SharedPreferencesManager;
 import org.chromium.components.signin.AccountManagerDelegate;
 import org.chromium.components.signin.AccountManagerDelegateException;
 import org.chromium.components.signin.AccountManagerFacade;
@@ -53,8 +54,8 @@
 
         mReceiver.onReceive(RuntimeEnvironment.application, intent);
         Assert.assertFalse(ToSAckedReceiver.checkAnyUserHasSeenToS());
-        Set<String> toSAckedAccounts = ContextUtils.getAppSharedPreferences().getStringSet(
-                ToSAckedReceiver.TOS_ACKED_ACCOUNTS, new HashSet<>());
+        Set<String> toSAckedAccounts = SharedPreferencesManager.getInstance().readStringSet(
+                ChromePreferenceKeys.TOS_ACKED_ACCOUNTS, new HashSet<>());
         Assert.assertThat(toSAckedAccounts, Matchers.contains(GOOGLE_ACCOUNT));
 
         AccountManagerDelegate accountManagerDelegate = Mockito.mock(AccountManagerDelegate.class);
diff --git a/chrome/android/native_java_unittests/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java b/chrome/android/native_java_unittests/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java
index 5ea18b17e..1da8f237 100644
--- a/chrome/android/native_java_unittests/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java
+++ b/chrome/android/native_java_unittests/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java
@@ -4,6 +4,9 @@
 package org.chromium.chrome.browser.toolbar;
 
 import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.when;
 
 import org.mockito.Mock;
@@ -35,6 +38,7 @@
     @Mock
     SecurityStateModel.Natives mSecurityStateMocks;
 
+    @Mock
     private LocationBarModel mLocationBarModel;
 
     @CalledByNative
@@ -44,7 +48,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         SecurityStateModelJni.TEST_HOOKS.setInstanceForTesting(mSecurityStateMocks);
-        mLocationBarModel = new LocationBarModel(ContextUtils.getApplicationContext());
+        mLocationBarModel = spy(new LocationBarModel(ContextUtils.getApplicationContext()));
         mLocationBarModel.initializeWithNative();
     }
 
@@ -56,30 +60,34 @@
     @CalledByNativeJavaTest
     public void testGetSecurityLevel() {
         assertEquals(ConnectionSecurityLevel.NONE,
-                LocationBarModel.getSecurityLevel(null, !IS_OFFLINE_PAGE, null));
+                mLocationBarModel.getSecurityLevel(null, !IS_OFFLINE_PAGE, null));
         assertEquals(ConnectionSecurityLevel.NONE,
-                LocationBarModel.getSecurityLevel(null, IS_OFFLINE_PAGE, null));
+                mLocationBarModel.getSecurityLevel(null, IS_OFFLINE_PAGE, null));
         assertEquals(ConnectionSecurityLevel.NONE,
-                LocationBarModel.getSecurityLevel(mTab, IS_OFFLINE_PAGE, null));
+                mLocationBarModel.getSecurityLevel(mTab, IS_OFFLINE_PAGE, null));
 
         for (int securityLevel : SECURITY_LEVELS) {
-            when((mTab).getSecurityLevel()).thenReturn(securityLevel);
+            doReturn(securityLevel).when(mLocationBarModel).getSecurityLevelFromStateModel(any());
             assertEquals("Wrong security level returned for " + securityLevel, securityLevel,
-                    LocationBarModel.getSecurityLevel(mTab, !IS_OFFLINE_PAGE, null));
+                    mLocationBarModel.getSecurityLevel(mTab, !IS_OFFLINE_PAGE, null));
         }
 
-        when((mTab).getSecurityLevel()).thenReturn(ConnectionSecurityLevel.SECURE);
+        doReturn(ConnectionSecurityLevel.SECURE)
+                .when(mLocationBarModel)
+                .getSecurityLevelFromStateModel(any());
         assertEquals("Wrong security level returned for HTTPS publisher URL",
                 ConnectionSecurityLevel.SECURE,
-                LocationBarModel.getSecurityLevel(mTab, !IS_OFFLINE_PAGE, "https://example.com"));
+                mLocationBarModel.getSecurityLevel(mTab, !IS_OFFLINE_PAGE, "https://example.com"));
         assertEquals("Wrong security level returned for HTTP publisher URL",
                 ConnectionSecurityLevel.WARNING,
-                LocationBarModel.getSecurityLevel(mTab, !IS_OFFLINE_PAGE, "http://example.com"));
+                mLocationBarModel.getSecurityLevel(mTab, !IS_OFFLINE_PAGE, "http://example.com"));
 
-        when((mTab).getSecurityLevel()).thenReturn(ConnectionSecurityLevel.DANGEROUS);
+        doReturn(ConnectionSecurityLevel.DANGEROUS)
+                .when(mLocationBarModel)
+                .getSecurityLevelFromStateModel(any());
         assertEquals("Wrong security level returned for publisher URL on insecure page",
                 ConnectionSecurityLevel.DANGEROUS,
-                LocationBarModel.getSecurityLevel(mTab, !IS_OFFLINE_PAGE, null));
+                mLocationBarModel.getSecurityLevel(mTab, !IS_OFFLINE_PAGE, null));
     }
 
     @CalledByNativeJavaTest
diff --git a/chrome/app/chrome_command_ids.h b/chrome/app/chrome_command_ids.h
index f2670c8..01a2246 100644
--- a/chrome/app/chrome_command_ids.h
+++ b/chrome/app/chrome_command_ids.h
@@ -395,6 +395,12 @@
 #define IDC_CONTENT_CONTEXT_ACCESSIBILITY_LABELS 52411
 #define IDC_CONTENT_CONTEXT_ACCESSIBILITY_LABELS_TOGGLE_ONCE 52412
 
+#if defined(OS_CHROMEOS)
+// Quick Answers context menu items.
+#define IDC_CONTENT_CONTEXT_QUICK_ANSWERS_INLINE_ANSWER 52413
+#define IDC_CONTENT_CONTEXT_QUICK_ANSWERS_INLINE_QUERY 52414
+#endif
+
 // NOTE: The last valid command value is 57343 (0xDFFF)
 // See http://msdn.microsoft.com/en-us/library/t2zechd4(VS.71).aspx
 
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index dcd06a6..e7025a79 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -10510,10 +10510,10 @@
       Timed out
     </message>
     <message name="IDS_DEEP_SCANNING_TIMED_OUT_DIALOG_MESSAGE" desc="Message shown in tab modal dialog when the deep scanning times out.">
-      Something went wrong. The scanned file has timed out.
+      Something went wrong. Scanning could not be completed. Please try again.
     </message>
     <message name="IDS_DEEP_SCANNING_TIMED_OUT_DIALOG_ACCEPT_BUTTON" desc="The text on the accept button in tab modal dialog when deep scanning times out.">
-      Scan
+      Scan again
     </message>
     <message name="IDS_DEEP_SCANNING_TIMED_OUT_DIALOG_CANCEL_BUTTON" desc="The text on the cancel button in tab modal dialog when deep scanning times out.">
       Cancel
diff --git a/chrome/app/vector_icons/BUILD.gn b/chrome/app/vector_icons/BUILD.gn
index 4935e7a1..4918da1c 100644
--- a/chrome/app/vector_icons/BUILD.gn
+++ b/chrome/app/vector_icons/BUILD.gn
@@ -224,6 +224,10 @@
       "google_chrome/google_pay_logo.icon",
     ]
   }
+
+  if (is_chrome_branded && is_chromeos) {
+    icons += [ "google_chrome/assistant.icon" ]
+  }
 }
 
 source_set("vector_icons") {
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index e58c6b5..134f644 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -2592,6 +2592,8 @@
       "android/preferences/browser_prefs_android.h",
       "android/preferences/clipboard_android.cc",
       "android/preferences/clipboard_android.h",
+      "android/preferences/cookie_controls_bridge.cc",
+      "android/preferences/cookie_controls_bridge.h",
       "android/preferences/pref_change_registrar_android.cc",
       "android/preferences/pref_change_registrar_android.h",
       "android/preferences/pref_service_bridge.cc",
@@ -3817,6 +3819,8 @@
       "notifications/web_page_notifier_controller.h",
       "policy/default_geolocation_policy_handler.cc",
       "policy/default_geolocation_policy_handler.h",
+      "renderer_context_menu/quick_answers_menu_observer.cc",
+      "renderer_context_menu/quick_answers_menu_observer.h",
       "signin/signin_error_notifier_ash.cc",
       "signin/signin_error_notifier_ash.h",
       "signin/signin_error_notifier_factory_ash.cc",
@@ -3851,6 +3855,7 @@
       "//chrome/browser/chromeos",
       "//chrome/services/app_service/public/cpp:instance_update",
       "//chromeos/components/account_manager",
+      "//chromeos/components/quick_answers",
       "//chromeos/components/sync_wifi",
       "//chromeos/services/assistant/public:feature_flags",
       "//chromeos/services/assistant/public/cpp:prefs",
@@ -4724,6 +4729,7 @@
       "//chrome/browser/web_applications",
 
       # TODO(loyso): Erase these. crbug.com/877898.
+      "//chrome/browser/web_applications:common",
       "//chrome/browser/web_applications:web_applications_on_extensions",
       "//chrome/browser/web_applications/components",
       "//chrome/browser/web_applications/extensions",
@@ -4732,6 +4738,7 @@
       "//apps",
       "//chrome/browser/sync_file_system/drive_backend:sync_file_system_drive_proto",
       "//chrome/browser/web_applications",
+      "//chrome/browser/web_applications:common",
       "//chrome/browser/web_applications:web_applications_on_extensions",
       "//chrome/browser/web_applications/components",
       "//chrome/browser/web_applications/extensions",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index f6fbd20..a84f8e94 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2577,6 +2577,13 @@
      kOsCrOS,
      SINGLE_VALUE_TYPE(
          ::switches::kEnableExperimentalAccessibilitySwitchAccessText)},
+    {"enable-experimental-accessibility-chromevox-annotations",
+     flag_descriptions::kExperimentalAccessibilityChromeVoxAnnotationsName,
+     flag_descriptions::
+         kExperimentalAccessibilityChromeVoxAnnotationsDescription,
+     kOsCrOS,
+     SINGLE_VALUE_TYPE(
+         ::switches::kEnableExperimentalAccessibilityChromeVoxAnnotations)},
     {"enable-experimental-accessibility-chromevox-language-switching",
      flag_descriptions::
          kExperimentalAccessibilityChromeVoxLanguageSwitchingName,
diff --git a/chrome/browser/android/chrome_feature_list.cc b/chrome/browser/android/chrome_feature_list.cc
index a8d3e01..fbb9c9d9 100644
--- a/chrome/browser/android/chrome_feature_list.cc
+++ b/chrome/browser/android/chrome_feature_list.cc
@@ -183,7 +183,6 @@
     &kSearchEnginePromoNewDevice,
     &kServiceManagerForBackgroundPrefetch,
     &kServiceManagerForDownload,
-    &kSettingsModernStatusBar,
     &kSharedClipboardUI,
     &kSharingQrCodeAndroid,
     &kShoppingAssist,
@@ -545,9 +544,6 @@
 const base::Feature kServiceManagerForDownload{
     "ServiceManagerForDownload", base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kSettingsModernStatusBar{"SettingsModernStatusBar",
-                                             base::FEATURE_ENABLED_BY_DEFAULT};
-
 const base::Feature kShoppingAssist{"ShoppingAssist",
                                     base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/chrome/browser/android/chrome_feature_list.h b/chrome/browser/android/chrome_feature_list.h
index a31e391..057545a 100644
--- a/chrome/browser/android/chrome_feature_list.h
+++ b/chrome/browser/android/chrome_feature_list.h
@@ -106,7 +106,6 @@
 extern const base::Feature kSearchEnginePromoNewDevice;
 extern const base::Feature kServiceManagerForBackgroundPrefetch;
 extern const base::Feature kServiceManagerForDownload;
-extern const base::Feature kSettingsModernStatusBar;
 extern const base::Feature kShoppingAssist;
 extern const base::Feature kSpannableInlineAutocomplete;
 extern const base::Feature kSpecialLocaleWrapper;
diff --git a/chrome/browser/android/preferences/cookie_controls_bridge.cc b/chrome/browser/android/preferences/cookie_controls_bridge.cc
new file mode 100644
index 0000000..8cbd7823
--- /dev/null
+++ b/chrome/browser/android/preferences/cookie_controls_bridge.cc
@@ -0,0 +1,63 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/android/preferences/cookie_controls_bridge.h"
+
+#include <memory>
+#include "chrome/android/chrome_jni_headers/CookieControlsBridge_jni.h"
+
+using base::android::JavaParamRef;
+
+CookieControlsBridge::CookieControlsBridge(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    const base::android::JavaParamRef<jobject>& jweb_contents_android)
+    : jobject_(obj) {
+  content::WebContents* web_contents =
+      content::WebContents::FromJavaWebContents(jweb_contents_android);
+  controller_ = std::make_unique<CookieControlsController>(web_contents);
+  observer_.Add(controller_.get());
+  controller_->Update(web_contents);
+}
+
+void CookieControlsBridge::OnStatusChanged(
+    CookieControlsController::Status new_status,
+    int blocked_cookies) {
+  if (status_ != new_status) {
+    status_ = new_status;
+    JNIEnv* env = base::android::AttachCurrentThread();
+    // Only call status callback if status has changed
+    Java_CookieControlsBridge_onCookieBlockingStatusChanged(
+        env, jobject_, static_cast<int>(status_));
+  }
+
+  OnBlockedCookiesCountChanged(blocked_cookies);
+}
+
+void CookieControlsBridge::OnBlockedCookiesCountChanged(int blocked_cookies) {
+  // The blocked cookie count changes quite frequently, so avoid unnecessary
+  // UI updates if possible.
+  if (blocked_cookies_ == blocked_cookies)
+    return;
+
+  blocked_cookies_ = blocked_cookies;
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_CookieControlsBridge_onBlockedCookiesCountChanged(
+      env, jobject_, blocked_cookies_.value_or(0));
+}
+
+CookieControlsBridge::~CookieControlsBridge() = default;
+
+void CookieControlsBridge::Destroy(JNIEnv* env,
+                                   const JavaParamRef<jobject>& obj) {
+  delete this;
+}
+
+static jlong JNI_CookieControlsBridge_Init(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    const base::android::JavaParamRef<jobject>& jweb_contents_android) {
+  return reinterpret_cast<intptr_t>(
+      new CookieControlsBridge(env, obj, jweb_contents_android));
+}
diff --git a/chrome/browser/android/preferences/cookie_controls_bridge.h b/chrome/browser/android/preferences/cookie_controls_bridge.h
new file mode 100644
index 0000000..0c4fa16
--- /dev/null
+++ b/chrome/browser/android/preferences/cookie_controls_bridge.h
@@ -0,0 +1,45 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_ANDROID_PREFERENCES_COOKIE_CONTROLS_BRIDGE_H_
+#define CHROME_BROWSER_ANDROID_PREFERENCES_COOKIE_CONTROLS_BRIDGE_H_
+
+#include "base/android/jni_weak_ref.h"
+#include "base/optional.h"
+#include "chrome/browser/ui/cookie_controls/cookie_controls_controller.h"
+#include "chrome/browser/ui/cookie_controls/cookie_controls_view.h"
+
+// Communicates between CookieControlsController (C++ backend) and PageInfoView
+// (Java UI).
+class CookieControlsBridge : public CookieControlsView {
+ public:
+  // Creates a CookeControlsBridge for interaction with a
+  // CookieControlsController.
+  CookieControlsBridge(
+      JNIEnv* env,
+      const base::android::JavaParamRef<jobject>& obj,
+      const base::android::JavaParamRef<jobject>& jweb_contents_android);
+
+  ~CookieControlsBridge() override;
+
+  // Called by the Java counterpart when it is getting garbage collected.
+  void Destroy(JNIEnv* env, const base::android::JavaParamRef<jobject>& obj);
+
+  // CookieControlsView:
+  void OnStatusChanged(CookieControlsController::Status status,
+                       int blocked_cookies) override;
+  void OnBlockedCookiesCountChanged(int blocked_cookies) override;
+
+ private:
+  base::android::ScopedJavaGlobalRef<jobject> jobject_;
+  CookieControlsController::Status status_ =
+      CookieControlsController::Status::kUninitialized;
+  base::Optional<int> blocked_cookies_;
+  std::unique_ptr<CookieControlsController> controller_;
+  ScopedObserver<CookieControlsController, CookieControlsView> observer_{this};
+
+  DISALLOW_COPY_AND_ASSIGN(CookieControlsBridge);
+};
+
+#endif  // CHROME_BROWSER_ANDROID_PREFERENCES_COOKIE_CONTROLS_BRIDGE_H_
diff --git a/chrome/browser/apps/platform_apps/shortcut_manager.cc b/chrome/browser/apps/platform_apps/shortcut_manager.cc
index 00966cd2..93ce9f91 100644
--- a/chrome/browser/apps/platform_apps/shortcut_manager.cc
+++ b/chrome/browser/apps/platform_apps/shortcut_manager.cc
@@ -162,6 +162,7 @@
     const Extension* extension,
     extensions::UninstallReason reason) {
 #if defined(OS_MACOSX)
+  // TODO(crbug.com/860581): Move this code to BookmarkAppShortcutManager.
   if (UseAppShimRegistry(browser_context, extension)) {
     bool delete_multi_profile_shortcuts =
         AppShimRegistry::Get()->OnAppUninstalledForProfile(extension->id(),
@@ -175,7 +176,10 @@
   }
 #endif
 
-  web_app::DeleteAllShortcuts(profile_, extension);
+  // Bookmark apps are handled in
+  // web_app::AppShortcutManager::OnWebAppWillBeUninstalled()
+  if (!extension->from_bookmark())
+    web_app::DeleteAllShortcuts(profile_, extension);
 }
 
 void AppShortcutManager::OnProfileWillBeRemoved(
diff --git a/chrome/browser/apps/platform_apps/shortcut_manager.h b/chrome/browser/apps/platform_apps/shortcut_manager.h
index a45d483..1f4aa1a 100644
--- a/chrome/browser/apps/platform_apps/shortcut_manager.h
+++ b/chrome/browser/apps/platform_apps/shortcut_manager.h
@@ -20,7 +20,11 @@
 class PrefRegistrySyncable;
 }
 
-// This class manages the installation of shortcuts for platform apps.
+// This class manages the installation of shortcuts for any extension-based apps
+// (Chrome Apps). Bookmark apps OS shortcut management is handled in
+// web_app::AppShortcutManager and its subclasses.
+//
+// Long term, this class must be deleted together with all extension-based apps.
 class AppShortcutManager : public KeyedService,
                            public extensions::ExtensionRegistryObserver,
                            public ProfileAttributesStorage::Observer {
diff --git a/chrome/browser/chromeos/child_accounts/time_limits/web_time_limit_navigation_throttle.cc b/chrome/browser/chromeos/child_accounts/time_limits/web_time_limit_navigation_throttle.cc
index 1ecd9fe..729d529 100644
--- a/chrome/browser/chromeos/child_accounts/time_limits/web_time_limit_navigation_throttle.cc
+++ b/chrome/browser/chromeos/child_accounts/time_limits/web_time_limit_navigation_throttle.cc
@@ -18,7 +18,7 @@
 #include "chrome/browser/ui/web_applications/app_browser_controller.h"
 #include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
-#include "chrome/browser/web_applications/components/web_app_tab_helper.h"
+#include "chrome/browser/web_applications/components/web_app_tab_helper_base.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/web_contents.h"
@@ -129,15 +129,13 @@
   const std::string& app_locale = g_browser_process->GetApplicationLocale();
 
   Browser::Type type = browser->type();
-  web_app::WebAppTabHelper* web_app_helper =
-      web_app::WebAppTabHelper::FromWebContents(web_contents);
+  web_app::WebAppTabHelperBase* web_app_helper =
+      web_app::WebAppTabHelperBase::FromWebContents(web_contents);
 
   bool is_windowed = (type == Browser::Type::TYPE_APP_POPUP) ||
                      (type == Browser::Type::TYPE_APP) ||
                      (type == Browser::Type::TYPE_POPUP);
-  bool is_app = false;
-  if (web_app_helper && !web_app_helper->app_id().empty())
-    is_app = true;
+  bool is_app = web_app_helper && !web_app_helper->GetAppId().empty();
 
   // Don't throttle windowed applications. We show a notification and close
   // them.
@@ -152,7 +150,7 @@
         web_app::WebAppProvider::Get(profile);
     const web_app::AppRegistrar& registrar = web_app_provider->registrar();
     const std::string& app_name =
-        registrar.GetAppShortName(web_app_helper->app_id());
+        registrar.GetAppShortName(web_app_helper->GetAppId());
     interstitial_html =
         GetWebTimeLimitAppErrorPage(time_limit, app_locale, app_name);
   } else {
diff --git a/chrome/browser/chromeos/first_run/first_run.cc b/chrome/browser/chromeos/first_run/first_run.cc
index f69dedc..4d39b1e 100644
--- a/chrome/browser/chromeos/first_run/first_run.cc
+++ b/chrome/browser/chromeos/first_run/first_run.cc
@@ -8,8 +8,8 @@
 #include "base/command_line.h"
 #include "base/macros.h"
 #include "base/metrics/histogram_macros.h"
-#include "chrome/browser/apps/app_service/app_launch_params.h"
-#include "chrome/browser/apps/launch_service/launch_service.h"
+#include "chrome/browser/apps/app_service/app_service_proxy.h"
+#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/first_run/first_run_controller.h"
@@ -38,6 +38,8 @@
 #include "content/public/common/content_switches.h"
 #include "extensions/browser/extension_registry.h"
 #include "extensions/common/constants.h"
+#include "ui/display/types/display_constants.h"
+#include "ui/events/event_constants.h"
 #include "ui/gfx/geometry/rect.h"
 
 namespace chromeos {
@@ -45,33 +47,34 @@
 
 namespace {
 
-void LaunchDialogForProfile(Profile* profile) {
+void LaunchHelpForProfile(Profile* profile) {
   extensions::ExtensionRegistry* registry =
       extensions::ExtensionRegistry::Get(profile);
   if (!registry)
     return;
 
-  const extensions::Extension* extension =
-      registry->GetExtensionById(extension_misc::kFirstRunDialogId,
-                                 extensions::ExtensionRegistry::ENABLED);
+  const extensions::Extension* extension = registry->GetExtensionById(
+      extension_misc::kGeniusAppId, extensions::ExtensionRegistry::ENABLED);
   if (!extension)
     return;
 
-  apps::LaunchService::Get(profile)->OpenApplication(apps::AppLaunchParams(
-      extension->id(), apps::mojom::LaunchContainer::kLaunchContainerWindow,
-      WindowOpenDisposition::NEW_WINDOW,
-      apps::mojom::AppLaunchSource::kSourceChromeInternal));
+  apps::AppServiceProxy* proxy =
+      apps::AppServiceProxyFactory::GetForProfile(profile);
+  DCHECK(proxy);
+  proxy->Launch(extension->id(), ui::EventFlags::EF_NONE,
+                apps::mojom::LaunchSource::kFromChromeInternal,
+                display::kInvalidDisplayId);
   profile->GetPrefs()->SetBoolean(prefs::kFirstRunTutorialShown, true);
 }
 
-void TryLaunchFirstRunDialog(Profile* profile) {
+void TryLaunchHelpApp(Profile* profile) {
   base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
 
   if (chromeos::switches::ShouldSkipOobePostLogin())
     return;
 
   if (command_line->HasSwitch(switches::kForceFirstRunUI)) {
-    LaunchDialogForProfile(profile);
+    LaunchHelpForProfile(profile);
     return;
   }
 
@@ -98,19 +101,16 @@
   if (!is_pref_synced && is_user_ephemeral)
     return;
 
-  LaunchDialogForProfile(profile);
+  LaunchHelpForProfile(profile);
 }
 
-// Object of this class waits for session start. Then it launches or not
-// launches first-run dialog depending on user prefs and flags. Than object
-// deletes itself.
-class DialogLauncher : public session_manager::SessionManagerObserver {
+// Object of this class waits for session start. Then it maybe launches the help
+// app depending on user prefs and flags. The object then deletes itself.
+class AppLauncher : public session_manager::SessionManagerObserver {
  public:
-  DialogLauncher() {
-    session_manager::SessionManager::Get()->AddObserver(this);
-  }
+  AppLauncher() { session_manager::SessionManager::Get()->AddObserver(this); }
 
-  ~DialogLauncher() override {
+  ~AppLauncher() override {
     session_manager::SessionManager::Get()->RemoveObserver(this);
   }
 
@@ -118,12 +118,12 @@
   void OnUserSessionStarted(bool is_primary_user) override {
     auto* profile = ProfileHelper::Get()->GetProfileByUser(
         user_manager::UserManager::Get()->GetActiveUser());
-    TryLaunchFirstRunDialog(profile);
+    TryLaunchHelpApp(profile);
     delete this;
   }
 
  private:
-  DISALLOW_COPY_AND_ASSIGN(DialogLauncher);
+  DISALLOW_COPY_AND_ASSIGN(AppLauncher);
 };
 
 }  // namespace
@@ -135,8 +135,8 @@
   registry->RegisterBooleanPref(prefs::kFirstRunTutorialShown, false);
 }
 
-void MaybeLaunchDialogAfterSessionStart() {
-  new DialogLauncher();
+void MaybeLaunchHelpAppAfterSessionStart() {
+  new AppLauncher();
 }
 
 void LaunchTutorial() {
diff --git a/chrome/browser/chromeos/first_run/first_run.h b/chrome/browser/chromeos/first_run/first_run.h
index 45b984d..91cb317 100644
--- a/chrome/browser/chromeos/first_run/first_run.h
+++ b/chrome/browser/chromeos/first_run/first_run.h
@@ -15,10 +15,10 @@
 // Registers preferences related to ChromeOS first-run tutorial.
 void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
 
-// Probably launches first-run dialog after session start depending on synced
-// user prefs. This method should be called after user already logged in but
-// session didn't started yet.
-void MaybeLaunchDialogAfterSessionStart();
+// Maybe launches the help app after session start (depending on synced user
+// prefs and flags). This method should be called after the user has already
+// logged in and before the session starts.
+void MaybeLaunchHelpAppAfterSessionStart();
 
 // Launches overlay tutorial for current user.
 void LaunchTutorial();
diff --git a/chrome/browser/chromeos/login/session/user_session_manager.cc b/chrome/browser/chromeos/login/session/user_session_manager.cc
index 645e4ce..25325f6a 100644
--- a/chrome/browser/chromeos/login/session/user_session_manager.cc
+++ b/chrome/browser/chromeos/login/session/user_session_manager.cc
@@ -1821,7 +1821,7 @@
     // background.
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
         ::switches::kSilentLaunch);
-    first_run::MaybeLaunchDialogAfterSessionStart();
+    first_run::MaybeLaunchHelpAppAfterSessionStart();
   } else {
     for (size_t i = 0; i < start_urls.size(); ++i) {
       base::CommandLine::ForCurrentProcess()->AppendArg(start_urls[i]);
diff --git a/chrome/browser/download/chrome_download_manager_delegate.cc b/chrome/browser/download/chrome_download_manager_delegate.cc
index 94a21e7..dcf1ef9 100644
--- a/chrome/browser/download/chrome_download_manager_delegate.cc
+++ b/chrome/browser/download/chrome_download_manager_delegate.cc
@@ -1108,6 +1108,10 @@
 
   DVLOG(2) << __func__ << "() download = " << item->DebugString(false)
            << " verdict = " << static_cast<int>(result);
+
+  // Indicates whether we expect future verdicts on this download. For example,
+  // if Safe Browsing is performing deep scanning, we will receive a more
+  // specific verdict later.
   bool is_pending_scanning = false;
 
   // We only mark the content as being dangerous if the download's safety state
@@ -1171,6 +1175,10 @@
       case safe_browsing::DownloadCheckResult::DEEP_SCANNED_SAFE:
         danger_type = download::DOWNLOAD_DANGER_TYPE_DEEP_SCANNED_SAFE;
         break;
+      case safe_browsing::DownloadCheckResult::PROMPT_FOR_SCANNING:
+        danger_type = download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING;
+        is_pending_scanning = true;
+        break;
     }
     DCHECK_NE(danger_type,
               download::DOWNLOAD_DANGER_TYPE_MAYBE_DANGEROUS_CONTENT);
diff --git a/chrome/browser/extensions/api/declarative_net_request/ruleset_manager_unittest.cc b/chrome/browser/extensions/api/declarative_net_request/ruleset_manager_unittest.cc
index fe189fd..c8359a9 100644
--- a/chrome/browser/extensions/api/declarative_net_request/ruleset_manager_unittest.cc
+++ b/chrome/browser/extensions/api/declarative_net_request/ruleset_manager_unittest.cc
@@ -275,7 +275,7 @@
 }
 
 // Tests that
-// Extensions.DeclarativeNetRequest.EvaluateRequestTime.AllExtensions2
+// Extensions.DeclarativeNetRequest.EvaluateRequestTime.AllExtensions3
 // is only emitted when there are active rulesets.
 TEST_P(RulesetManagerTest, TotalEvaluationTimeHistogram) {
   WebRequestInfo example_com_request(
@@ -284,7 +284,7 @@
       GetRequestParamsForURL("http://google.com"));
   bool is_incognito_context = false;
   const char* kHistogramName =
-      "Extensions.DeclarativeNetRequest.EvaluateRequestTime.AllExtensions2";
+      "Extensions.DeclarativeNetRequest.EvaluateRequestTime.AllExtensions3";
   {
     base::HistogramTester tester;
 
diff --git a/chrome/browser/extensions/browsertest_util.cc b/chrome/browser/extensions/browsertest_util.cc
index 4f82758..cbc28e49 100644
--- a/chrome/browser/extensions/browsertest_util.cc
+++ b/chrome/browser/extensions/browsertest_util.cc
@@ -24,7 +24,7 @@
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/components/web_app_install_utils.h"
 #include "chrome/browser/web_applications/components/web_app_provider_base.h"
-#include "chrome/browser/web_applications/components/web_app_tab_helper.h"
+#include "chrome/browser/web_applications/components/web_app_tab_helper_base.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/common/web_application_info.h"
 #include "chrome/test/base/ui_test_utils.h"
diff --git a/chrome/browser/extensions/chrome_app_icon_loader.cc b/chrome/browser/extensions/chrome_app_icon_loader.cc
index 5476dba2..e7459fb 100644
--- a/chrome/browser/extensions/chrome_app_icon_loader.cc
+++ b/chrome/browser/extensions/chrome_app_icon_loader.cc
@@ -44,7 +44,12 @@
 bool ChromeAppIconLoader::CanLoadImageForApp(const std::string& id) {
   if (map_.find(id) != map_.end())
     return true;
-  return GetExtensionByID(profile(), id) != nullptr;
+
+  const Extension* extension = GetExtensionByID(profile(), id);
+  if (!extension || (extensions_only_ && !extension->is_extension()))
+    return false;
+
+  return true;
 }
 
 void ChromeAppIconLoader::FetchImage(const std::string& id) {
@@ -77,6 +82,10 @@
   it->second->UpdateIcon();
 }
 
+void ChromeAppIconLoader::SetExtensionsOnly() {
+  extensions_only_ = true;
+}
+
 void ChromeAppIconLoader::OnIconUpdated(ChromeAppIcon* icon) {
   delegate()->OnAppImageUpdated(icon->app_id(), icon->image_skia());
 }
diff --git a/chrome/browser/extensions/chrome_app_icon_loader.h b/chrome/browser/extensions/chrome_app_icon_loader.h
index f35ca2d..a5f64aa 100644
--- a/chrome/browser/extensions/chrome_app_icon_loader.h
+++ b/chrome/browser/extensions/chrome_app_icon_loader.h
@@ -48,6 +48,9 @@
   void ClearImage(const std::string& id) override;
   void UpdateImage(const std::string& id) override;
 
+  // Sets |extensions_only_| as true to load icons for extensions only.
+  void SetExtensionsOnly();
+
  private:
   using ExtensionIDToChromeAppIconMap =
       std::map<std::string, std::unique_ptr<ChromeAppIcon>>;
@@ -62,6 +65,10 @@
   // resize will be performed by ImageLoader.
   const ResizeFunction resize_function_;
 
+  // Loads icons for extensions only if true, otherwise loads icon for both
+  // Chrome apps and extensions.
+  bool extensions_only_ = false;
+
   DISALLOW_COPY_AND_ASSIGN(ChromeAppIconLoader);
 };
 
diff --git a/chrome/browser/extensions/chrome_app_icon_service.cc b/chrome/browser/extensions/chrome_app_icon_service.cc
index e5a184e..a718a39 100644
--- a/chrome/browser/extensions/chrome_app_icon_service.cc
+++ b/chrome/browser/extensions/chrome_app_icon_service.cc
@@ -21,7 +21,8 @@
 ChromeAppIconService::ChromeAppIconService(content::BrowserContext* context)
     : context_(context) {
 #if defined(OS_CHROMEOS)
-  app_updater_ = std::make_unique<LauncherExtensionAppUpdater>(this, context);
+  app_updater_ = std::make_unique<LauncherExtensionAppUpdater>(
+      this, context, false /* extensions_only */);
 #endif
 
   observer_.Add(ExtensionRegistry::Get(context_));
diff --git a/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc b/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc
index a8aef05f..e1c00c4 100644
--- a/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc
+++ b/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/extensions/extension_action_runner.h"
+#include <vector>
 
 #include "base/bind.h"
 #include "base/files/file_path.h"
@@ -32,6 +32,7 @@
 #include "content/public/test/test_navigation_observer.h"
 #include "extensions/browser/browsertest_util.h"
 #include "extensions/browser/url_loader_factory_manager.h"
+#include "extensions/common/extension_features.h"
 #include "extensions/test/test_extension_dir.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/controllable_http_response.h"
@@ -51,8 +52,11 @@
 enum TestParam {
   kAllowlisted = 1 << 0,
   kOutOfBlinkCors = 1 << 1,
+  kAllowlistForCors = 1 << 2,
 };
 
+const char kCorsErrorWhenFetching[] = "error: TypeError: Failed to fetch";
+
 }  // namespace
 
 using CORBAction = network::CrossOriginReadBlocking::Action;
@@ -359,13 +363,23 @@
   using Base = CrossOriginReadBlockingExtensionTest;
 
   CrossOriginReadBlockingExtensionAllowlistingTest() {
-    if (IsOutOfBlinkCorsEnabled()) {
-      scoped_feature_list_.InitAndEnableFeature(
-          network::features::kOutOfBlinkCors);
+    std::vector<base::Feature> disabled_features;
+    std::vector<base::Feature> enabled_features;
+
+    if (IsOutOfBlinkCorsEnabled())
+      enabled_features.push_back(network::features::kOutOfBlinkCors);
+    else
+      disabled_features.push_back(network::features::kOutOfBlinkCors);
+
+    if (ShouldAllowlistAlsoApplyToOorCors()) {
+      enabled_features.push_back(
+          extensions_features::kCorbAllowlistAlsoAppliesToOorCors);
     } else {
-      scoped_feature_list_.InitAndDisableFeature(
-          network::features::kOutOfBlinkCors);
+      disabled_features.push_back(
+          extensions_features::kCorbAllowlistAlsoAppliesToOorCors);
     }
+
+    scoped_feature_list_.InitWithFeatures(enabled_features, disabled_features);
   }
 
   bool IsExtensionAllowlisted() {
@@ -376,6 +390,10 @@
     return (GetParam() & TestParam::kOutOfBlinkCors) != 0;
   }
 
+  bool ShouldAllowlistAlsoApplyToOorCors() {
+    return (GetParam() & TestParam::kAllowlistForCors) != 0;
+  }
+
   const Extension* InstallExtension(
       GURL resource_to_fetch_from_declarative_content_script = GURL()) {
     const Extension* extension = Base::InstallExtension(
@@ -436,18 +454,31 @@
 
   // Verifies results of fetching a CORB-eligible resource from a content
   // script.  Expectations differ depending on the following:
-  // 1. Non-NetworkService: Fetches from content scripts should never be blocked
-  // 2. NetworkService + allowlisted extension: Fetches from content scripts
-  //                                            should not be blocked
-  // 3. NetworkService + other extension: Fetches from content scripts should
-  //                                      be blocked
+  // 1. Allowlisted extension: Fetches from content scripts
+  //                           should not be blocked
+  // 2. Other extension: Fetches from content scripts should be blocked by
+  //    either: only CORB or CORS+CORB.
   void VerifyFetchFromContentScript(const base::HistogramTester& histograms,
                                     const std::string& actual_fetch_result,
                                     const std::string& expected_fetch_result) {
     if (AreContentScriptFetchesExpectedToBeBlocked()) {
-      // Verify the fetch was blocked.
-      EXPECT_EQ(std::string(), actual_fetch_result);
-      VerifyFetchFromContentScriptWasBlocked(histograms);
+      if (ShouldAllowlistAlsoApplyToOorCors()) {
+        // Verify the fetch was blocked by CORS.
+        EXPECT_EQ(kCorsErrorWhenFetching, actual_fetch_result);
+
+        // No verification if the request was blocked by CORB, because
+        // 1) once request_initiator is trustworthy, CORB should only
+        //    apply to no-cors requests
+        // 2) some CORS-blocked requests may not reach CORB/response-started
+        //    stage at all (e.g. if CORS blocks a redirect).
+
+        // TODO(lukasza): Verify that the request was made in CORS mode (e.g.
+        // included an Origin header).
+      } else {
+        // Verify the fetch was blocked by CORB, but not blocked by CORS.
+        EXPECT_EQ(std::string(), actual_fetch_result);
+        VerifyFetchFromContentScriptWasBlocked(histograms);
+      }
     } else {
       // Verify the fetch was allowed.
       EXPECT_EQ(expected_fetch_result, actual_fetch_result);
@@ -667,13 +698,29 @@
       embedded_test_server()->GetURL("cross-site.com", "/save_page/text.txt"));
   std::string fetch_result =
       FetchViaContentScript(cross_site_resource, active_web_contents());
+  SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
 
-  // Verify that no blocking occurred.
-  EXPECT_THAT(fetch_result,
-              ::testing::StartsWith(
-                  "text-object.txt: ae52dd09-9746-4b7e-86a6-6ada5e2680c2"));
-  VerifyFetchFromContentScriptWasAllowed(histograms,
-                                         true /* expecting_sniffing */);
+  if (IsCorbExpectedToBeTurnedOffAltogether()) {
+    // Verify that CORB didn't run.
+    EXPECT_EQ(
+        0u,
+        histograms.GetTotalCountsForPrefix("SiteIsolation.XSD.Browser").size());
+  } else {
+    // Verify that CORB sniffing allowed the response.
+    VerifyFetchFromContentScriptWasAllowed(histograms,
+                                           true /* expecting_sniffing */);
+  }
+
+  if (ShouldAllowlistAlsoApplyToOorCors() &&
+      AreContentScriptFetchesExpectedToBeBlocked()) {
+    // Verify that the response body was blocked by CORS.
+    EXPECT_EQ(kCorsErrorWhenFetching, fetch_result);
+  } else {
+    // Verify that the response body was not blocked by either CORB nor CORS.
+    EXPECT_THAT(fetch_result,
+                ::testing::StartsWith(
+                    "text-object.txt: ae52dd09-9746-4b7e-86a6-6ada5e2680c2"));
+  }
 }
 
 // Test that responses are blocked by CORB, but have empty response body are not
@@ -696,14 +743,13 @@
   base::HistogramTester histograms;
   GURL cross_site_resource(
       embedded_test_server()->GetURL("cross-site.com", "/nosniff.empty"));
-  EXPECT_EQ(std::string(),
-            FetchViaContentScript(cross_site_resource, active_web_contents()));
+  std::string fetch_result =
+      FetchViaContentScript(cross_site_resource, active_web_contents());
 
-  // Verify whether blocking occurred or not.
-  if (AreContentScriptFetchesExpectedToBeBlocked())
-    VerifyFetchFromContentScriptWasBlocked(histograms);
-  else
-    VerifyFetchFromContentScriptWasAllowed(histograms);
+  // Verify whether the fetch worked or not (expectations differ depending on
+  // various factors - see the body of VerifyFetchFromContentScript).
+  VerifyFetchFromContentScript(histograms, fetch_result,
+                               "" /* expected_response_body */);
 }
 
 // Test that LogInitiatorSchemeBypassingDocumentBlocking exits early for
@@ -1130,6 +1176,9 @@
 
 IN_PROC_BROWSER_TEST_P(CrossOriginReadBlockingExtensionAllowlistingTest,
                        OriginHeaderInCrossOriginGetRequest) {
+  const char kResourcePath[] = "/simulated-resource";
+  net::test_server::ControllableHttpResponse http_request(
+      embedded_test_server(), kResourcePath);
   ASSERT_TRUE(embedded_test_server()->Start());
   ASSERT_TRUE(InstallExtension());
 
@@ -1144,45 +1193,45 @@
   // Inject a content script that performs a cross-origin GET fetch to
   // cross-site.com.
   GURL cross_site_resource(
-      embedded_test_server()->GetURL("cross-site.com", "/echoall"));
+      embedded_test_server()->GetURL("cross-site.com", kResourcePath));
   const char* kScriptTemplate = R"(
       fetch($1, {method: 'GET', mode:'cors'})
           .then(response => response.text())
           .then(text => domAutomationController.send(text))
           .catch(err => domAutomationController.send('ERROR: ' + err));
   )";
-  content::DOMMessageQueue message_queue;
   ExecuteContentScript(
       active_web_contents(),
       content::JsReplace(kScriptTemplate, cross_site_resource));
-  std::string fetch_result = PopString(&message_queue);
 
-  // Verify if the fetch was blocked + what the Origin header was.
-  if (AreContentScriptFetchesExpectedToBeBlocked()) {
-    // TODO(lukasza): https://crbug.com/953315: No CORB blocking should occur
-    // for the CORS-mode request - the test expectations should be the same,
-    // regardless of AreContentScriptFetchesExpectedToBeBlocked.
-    EXPECT_EQ("", fetch_result);
-  } else if (IsExtensionAllowlisted()) {
-    // Legacy behavior - no Origin: header is present in GET CORS requests from
-    // content scripts based on the extension permissions.
-    EXPECT_THAT(fetch_result, ::testing::Not(::testing::HasSubstr("Origin:")));
+  // Extract the Origin header.
+  http_request.WaitForRequest();
+  std::string actual_origin_header = "<none>";
+  const auto& headers_map = http_request.http_request()->headers;
+  auto it = headers_map.find("Origin");
+  if (it != headers_map.end())
+    actual_origin_header = it->second;
+
+  if (AreContentScriptFetchesExpectedToBeBlocked() &&
+      ShouldAllowlistAlsoApplyToOorCors()) {
+    // Verify the Origin header uses the page's origin (not the extension
+    // origin).
+    EXPECT_EQ(url::Origin::Create(page_url).Serialize(), actual_origin_header);
   } else {
-    // TODO(lukasza): https://crbug.com/920638: Non-allowlisted extension
-    // should use the website's origin in the CORS request.
-    // TODO: EXPECT_THAT(fetch_result,
-    //                   ::testing::HasSubstr("Origin:
-    //                   http://fetch-initiator.com"));
-    EXPECT_THAT(fetch_result, ::testing::Not(::testing::HasSubstr("Origin:")));
+    // Verify the Origin header is missing.
+    EXPECT_EQ("<none>", actual_origin_header);
   }
 
   // Regression test against https://crbug.com/944704.
-  EXPECT_THAT(fetch_result,
-              ::testing::Not(::testing::HasSubstr("Origin: chrome-extension")));
+  EXPECT_THAT(actual_origin_header,
+              ::testing::Not(::testing::HasSubstr("chrome-extension")));
 }
 
 IN_PROC_BROWSER_TEST_P(CrossOriginReadBlockingExtensionAllowlistingTest,
                        OriginHeaderInCrossOriginPostRequest) {
+  const char kResourcePath[] = "/simulated-resource";
+  net::test_server::ControllableHttpResponse http_request(
+      embedded_test_server(), kResourcePath);
   ASSERT_TRUE(embedded_test_server()->Start());
   ASSERT_TRUE(InstallExtension());
 
@@ -1197,33 +1246,32 @@
   // Inject a content script that performs a cross-origin POST fetch to
   // cross-site.com.
   GURL cross_site_resource(
-      embedded_test_server()->GetURL("cross-site.com", "/echoall"));
+      embedded_test_server()->GetURL("cross-site.com", kResourcePath));
   const char* kScriptTemplate = R"(
       fetch($1, {method: 'POST', mode:'cors'})
           .then(response => response.text())
           .then(text => domAutomationController.send(text))
           .catch(err => domAutomationController.send('ERROR: ' + err));
   )";
-  content::DOMMessageQueue message_queue;
   ExecuteContentScript(
       active_web_contents(),
       content::JsReplace(kScriptTemplate, cross_site_resource));
-  std::string fetch_result = PopString(&message_queue);
 
-  // Verify if the fetch was blocked + what the Origin header was.
-  if (AreContentScriptFetchesExpectedToBeBlocked()) {
-    // TODO(lukasza): https://crbug.com/953315: No CORB blocking should occur
-    // for the CORS-mode request - the test expectations should be the same,
-    // regardless of AreContentScriptFetchesExpectedToBeBlocked.
-    EXPECT_EQ("", fetch_result);
-  } else {
-    EXPECT_THAT(fetch_result,
-                ::testing::HasSubstr("Origin: http://fetch-initiator.com"));
-  }
+  // Extract the Origin header.
+  http_request.WaitForRequest();
+  std::string actual_origin_header = "<none>";
+  const auto& headers_map = http_request.http_request()->headers;
+  auto it = headers_map.find("Origin");
+  if (it != headers_map.end())
+    actual_origin_header = it->second;
+
+  // Verify the Origin header uses the page's origin (not the extension
+  // origin).
+  EXPECT_EQ(url::Origin::Create(page_url).Serialize(), actual_origin_header);
 
   // Regression test against https://crbug.com/944704.
-  EXPECT_THAT(fetch_result,
-              ::testing::Not(::testing::HasSubstr("Origin: chrome-extension")));
+  EXPECT_THAT(actual_origin_header,
+              ::testing::Not(::testing::HasSubstr("chrome-extension")));
 }
 
 IN_PROC_BROWSER_TEST_P(CrossOriginReadBlockingExtensionAllowlistingTest,
@@ -1421,6 +1469,15 @@
   EXPECT_EQ("cors-allowed-body", fetch_result);
 }
 
+INSTANTIATE_TEST_SUITE_P(Allowlisted_AllowlistForCors,
+                         CrossOriginReadBlockingExtensionAllowlistingTest,
+                         ::testing::Values(TestParam::kAllowlisted |
+                                           TestParam::kOutOfBlinkCors |
+                                           TestParam::kAllowlistForCors));
+INSTANTIATE_TEST_SUITE_P(NotAllowlisted_AllowlistForCors,
+                         CrossOriginReadBlockingExtensionAllowlistingTest,
+                         ::testing::Values(TestParam::kOutOfBlinkCors |
+                                           TestParam::kAllowlistForCors));
 INSTANTIATE_TEST_SUITE_P(Allowlisted_OorCors,
                          CrossOriginReadBlockingExtensionAllowlistingTest,
                          ::testing::Values(TestParam::kAllowlisted |
diff --git a/chrome/browser/file_select_helper.cc b/chrome/browser/file_select_helper.cc
index 2776f63..bb9a64c 100644
--- a/chrome/browser/file_select_helper.cc
+++ b/chrome/browser/file_select_helper.cc
@@ -110,6 +110,7 @@
     case Result::SENSITIVE_CONTENT_BLOCK:
     case Result::SENSITIVE_CONTENT_WARNING:
     case Result::DEEP_SCANNED_SAFE:
+    case Result::PROMPT_FOR_SCANNING:
       NOTREACHED();
       return true;
   }
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 335d74d4..e19e2dd 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -1305,6 +1305,11 @@
     "expiry_milestone": 78
   },
   {
+    "name": "enable-experimental-accessibility-chromevox-annotations",
+    "owners": ["akihiroota"],
+    "expiry_milestone": 86
+  },
+  {
     "name": "enable-experimental-accessibility-chromevox-language-switching",
     "owners": [ "akihiroota", "dmazzoni", "dtseng" ],
     "expiry_milestone": 82
@@ -3466,8 +3471,12 @@
   },
   {
     "name": "top-chrome-touch-ui",
-    "owners": [ "chrome-desktop-ui-sea@google.com" ],
-    "expiry_milestone": 81
+    "owners": [ "pbos", "chrome-desktop-ui-sea@google.com" ],
+    // This flag is used to easily swap into touch-mode for UI development where
+    // the UI differs significantly between touch/non-touch modes. This is
+    // exposed in chrome://flags to allow QA and UXers to verify touch-related
+    // behavior without access to touch devices.
+    "expiry_milestone": -1
   },
   {
     "name": "touch-events",
diff --git a/chrome/browser/flag-never-expire-list.json b/chrome/browser/flag-never-expire-list.json
index 2a02a54..bb5c231 100644
--- a/chrome/browser/flag-never-expire-list.json
+++ b/chrome/browser/flag-never-expire-list.json
@@ -81,6 +81,7 @@
   "show-taps",
   "show-touch-hud",
   "tint-gl-composited-content",
+  "top-chrome-touch-ui",
   "translate-android-manual-trigger",
   "ui-disable-partial-swap",
   "ui-slow-animations",
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 2791f91e..176d948 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -3604,6 +3604,11 @@
     "Allow Linux applications to request a pointer lock, i.e. exclusive use of "
     "the mouse pointer.";
 
+const char kExperimentalAccessibilityChromeVoxAnnotationsName[] =
+    "Enable experimental ChromeVox annotations feature.";
+const char kExperimentalAccessibilityChromeVoxAnnotationsDescription[] =
+    "Allows users to create custom annotations for elements using ChromeVox.";
+
 const char kExperimentalAccessibilityChromeVoxLanguageSwitchingName[] =
     "Enable experimental ChromeVox language switching.";
 const char kExperimentalAccessibilityChromeVoxLanguageSwitchingDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index 2ef68bf3..5f3ef37 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -2151,6 +2151,9 @@
 extern const char kExoPointerLockName[];
 extern const char kExoPointerLockDescription[];
 
+extern const char kExperimentalAccessibilityChromeVoxAnnotationsName[];
+extern const char kExperimentalAccessibilityChromeVoxAnnotationsDescription[];
+
 extern const char kExperimentalAccessibilityChromeVoxLanguageSwitchingName[];
 extern const char
     kExperimentalAccessibilityChromeVoxLanguageSwitchingDescription[];
diff --git a/chrome/browser/native_file_system/chrome_native_file_system_permission_context.cc b/chrome/browser/native_file_system/chrome_native_file_system_permission_context.cc
index a124624..1bb70f7 100644
--- a/chrome/browser/native_file_system/chrome_native_file_system_permission_context.cc
+++ b/chrome/browser/native_file_system/chrome_native_file_system_permission_context.cc
@@ -391,6 +391,7 @@
     case Result::SENSITIVE_CONTENT_WARNING:
     case Result::SENSITIVE_CONTENT_BLOCK:
     case Result::DEEP_SCANNED_SAFE:
+    case Result::PROMPT_FOR_SCANNING:
       NOTREACHED();
       return ChromeNativeFileSystemPermissionContext::AfterWriteCheckResult::
           kAllow;
diff --git a/chrome/browser/net/profile_network_context_service.cc b/chrome/browser/net/profile_network_context_service.cc
index 256f03fd..663b997 100644
--- a/chrome/browser/net/profile_network_context_service.cc
+++ b/chrome/browser/net/profile_network_context_service.cc
@@ -349,9 +349,9 @@
       prefs::kAmbientAuthenticationInPrivateModesEnabled,
       static_cast<int>(net::AmbientAuthAllowedProfileTypes::REGULAR_ONLY));
 
-  // For information about whether to reset the HTTP Cache or not, store the
-  // groups for all the relevant experiments.  Initially unknown status for all.
-  registry->RegisterStringPref(kHttpCacheFinchExperimentGroups, "NoneNoneNone");
+  // For information about whether to reset the HTTP Cache or not, defaults
+  // to the empty string, which does not prompt a reset.
+  registry->RegisterStringPref(kHttpCacheFinchExperimentGroups, "");
 }
 
 void ProfileNetworkContextService::DisableQuicIfNotAllowed() {
@@ -606,11 +606,11 @@
   base::FieldTrial* field_trial = base::FeatureList::GetFieldTrial(
       net::features::kSplitCacheByNetworkIsolationKey);
   std::string current_field_trial_status =
-      (field_trial ? field_trial->group_name() : "None");
+      (field_trial ? field_trial->group_name() : "None") + " ";
   field_trial = base::FeatureList::GetFieldTrial(
       net::features::kAppendFrameOriginToNetworkIsolationKey);
   current_field_trial_status +=
-      (field_trial ? field_trial->group_name() : "None");
+      (field_trial ? field_trial->group_name() : "None") + " ";
   field_trial = base::FeatureList::GetFieldTrial(
       net::features::kUseRegistrableDomainInNetworkIsolationKey);
   current_field_trial_status +=
@@ -621,7 +621,8 @@
   local_state->SetString(kHttpCacheFinchExperimentGroups,
                          current_field_trial_status);
 
-  return current_field_trial_status != previous_field_trial_status;
+  return !previous_field_trial_status.empty() &&
+         current_field_trial_status != previous_field_trial_status;
 }
 
 network::mojom::NetworkContextParamsPtr
diff --git a/chrome/browser/net/profile_network_context_service_browsertest.cc b/chrome/browser/net/profile_network_context_service_browsertest.cc
index bbacdd7..6d95543 100644
--- a/chrome/browser/net/profile_network_context_service_browsertest.cc
+++ b/chrome/browser/net/profile_network_context_service_browsertest.cc
@@ -17,6 +17,7 @@
 #include "base/task/thread_pool/thread_pool_instance.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
+#include "base/threading/platform_thread.h"  // For |Sleep()|.
 #include "base/threading/thread_restrictions.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
@@ -156,6 +157,29 @@
   EXPECT_TRUE(base::Contains(encodings, "br"));
 }
 
+void CheckCacheResetStatus(base::HistogramTester* histograms, bool reset) {
+  // TODO(crbug/1041810): The failure case, here, is to time out.  Since Chrome
+  // doesn't synchronize cache loading, there's no guarantee that this is
+  // complete and it's merely available at earliest convenience.  If shutdown
+  // occurs prior to the cache being loaded, then nothing is reported.  This
+  // should probably be fixed to avoid the use of the sleep function, but that
+  // will require synchronizing in some meaningful way to guarantee the cache
+  // has been loaded prior to testing the histograms.
+  while (!histograms->GetBucketCount("HttpCache.HardReset", reset)) {
+    content::FetchHistogramsFromChildProcesses();
+    SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
+    base::PlatformThread::Sleep(base::TimeDelta::FromMilliseconds(5));
+  }
+
+  if (reset) {
+    // Some tests load the cache multiple times, but should only be reset once.
+    EXPECT_EQ(histograms->GetBucketCount("HttpCache.HardReset", true), 1);
+  } else {
+    // Make sure it's never reset.
+    EXPECT_EQ(histograms->GetBucketCount("HttpCache.HardReset", true), 0);
+  }
+}
+
 class ProfileNetworkContextServiceCacheSameBrowsertest
     : public ProfileNetworkContextServiceBrowsertest {
  public:
@@ -170,40 +194,36 @@
     ProfileNetworkContextServiceBrowsertest::SetUp();
   }
 
-  void CheckCacheNotReset() {
-    content::FetchHistogramsFromChildProcesses();
-    SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
-    // Some tests load the cache multiple times, so compare to zero.
-    EXPECT_GT(histograms_.GetBucketCount("HttpCache.HardReset", false), 0);
-    // Make sure it's never reset.
-    EXPECT_EQ(histograms_.GetBucketCount("HttpCache.HardReset", true), 0);
-  }
+  base::HistogramTester histograms_;
 
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
-  base::HistogramTester histograms_;
 };
 
-// Flaky on Linux and Mac: https://crbug.com/1041810
-#if defined(OS_LINUX) || defined(OS_MACOSX)
-#define MAYBE_TestCacheResetParameter DISABLED_TestCacheResetParameter
-#else
-#define MAYBE_TestCacheResetParameter TestCacheResetParameter
-#endif
 IN_PROC_BROWSER_TEST_F(ProfileNetworkContextServiceCacheSameBrowsertest,
-                       MAYBE_TestCacheResetParameter) {
-  base::RunLoop().RunUntilIdle();
-  base::ThreadPoolInstance::Get()->FlushForTesting();
+                       PRE_TestCacheResetParameter) {
+  CheckCacheResetStatus(&histograms_, false);
 
-  // At this point, we have already called the initialization once on startup.
+  // At this point, we have already called the initialization.
   // Verify that we have the correct values in the local_state.
   PrefService* local_state = g_browser_process->local_state();
   DCHECK_EQ(
       local_state->GetString(
           "profile_network_context_service.http_cache_finch_experiment_groups"),
-      "NoneNoneNone");
+      "None None None");
+}
 
-  CheckCacheNotReset();
+IN_PROC_BROWSER_TEST_F(ProfileNetworkContextServiceCacheSameBrowsertest,
+                       TestCacheResetParameter) {
+  CheckCacheResetStatus(&histograms_, false);
+
+  // At this point, we have already called the initialization.
+  // Verify that we have the correct values in the local_state.
+  PrefService* local_state = g_browser_process->local_state();
+  DCHECK_EQ(
+      local_state->GetString(
+          "profile_network_context_service.http_cache_finch_experiment_groups"),
+      "None None None");
 }
 
 class ProfileNetworkContextServiceCacheChangeBrowsertest
@@ -217,33 +237,45 @@
   }
   ~ProfileNetworkContextServiceCacheChangeBrowsertest() override = default;
 
-  void CheckCacheReset() {
-    content::FetchHistogramsFromChildProcesses();
-    SubprocessMetricsProvider::MergeHistogramDeltasForTesting();
-    // Some tests load the cache multiple times, but should only be reset once.
-    EXPECT_EQ(histograms_.GetBucketCount("HttpCache.HardReset", true), 1);
-  }
+  base::HistogramTester histograms_;
 
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
-  base::HistogramTester histograms_;
 };
 
 // Flaky on Linux and Mac: https://crbug.com/1041810
+// The first time we load, even if we're in an experiment there's no reset
+// from the unknown state.
 IN_PROC_BROWSER_TEST_F(ProfileNetworkContextServiceCacheChangeBrowsertest,
-                       MAYBE_TestCacheResetParameter) {
-  base::RunLoop().RunUntilIdle();
-  base::ThreadPoolInstance::Get()->FlushForTesting();
+                       PRE_TestCacheResetParameter) {
+  CheckCacheResetStatus(&histograms_, false);
 
-  // At this point, we have already called the initialization once on startup.
+  // At this point, we have already called the initialization.
   // Verify that we have the correct values in the local_state.
   PrefService* local_state = g_browser_process->local_state();
   DCHECK_EQ(
       local_state->GetString(
           "profile_network_context_service.http_cache_finch_experiment_groups"),
-      "Nonescoped_feature_list_trial_groupNone");
+      "None scoped_feature_list_trial_group None");
+  // Set the local state for the next test.
+  local_state->SetString(
+      "profile_network_context_service.http_cache_finch_experiment_groups",
+      "None None None");
+}
 
-  CheckCacheReset();
+// The second time we load we know the state, which was "None None None" for the
+// previous test, so we should see a reset being in an experiment.
+IN_PROC_BROWSER_TEST_F(ProfileNetworkContextServiceCacheChangeBrowsertest,
+                       TestCacheResetParameter) {
+  CheckCacheResetStatus(&histograms_, true);
+
+  // At this point, we have already called the initialization once.
+  // Verify that we have the correct values in the local_state.
+  PrefService* local_state = g_browser_process->local_state();
+  DCHECK_EQ(
+      local_state->GetString(
+          "profile_network_context_service.http_cache_finch_experiment_groups"),
+      "None scoped_feature_list_trial_group None");
 }
 
 class AmbientAuthenticationTestWithPolicy
diff --git a/chrome/browser/notifications/notification_platform_bridge_linux.cc b/chrome/browser/notifications/notification_platform_bridge_linux.cc
index 735fff5..9ad0ca5e 100644
--- a/chrome/browser/notifications/notification_platform_bridge_linux.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_linux.cc
@@ -63,6 +63,7 @@
 // DBus methods.
 const char kMethodCloseNotification[] = "CloseNotification";
 const char kMethodGetCapabilities[] = "GetCapabilities";
+const char kMethodListActivatableNames[] = "ListActivatableNames";
 const char kMethodNameHasOwner[] = "NameHasOwner";
 const char kMethodNotify[] = "Notify";
 
@@ -251,7 +252,7 @@
   return resource_file;
 }
 
-bool CheckNotificationsNameHasOwner(dbus::Bus* bus) {
+bool CheckNotificationsNameHasOwnerOrIsActivatable(dbus::Bus* bus) {
   dbus::ObjectProxy* dbus_proxy =
       bus->GetObjectProxy(DBUS_SERVICE_DBUS, dbus::ObjectPath(DBUS_PATH_DBUS));
   dbus::MethodCall name_has_owner_call(DBUS_INTERFACE_DBUS,
@@ -263,7 +264,22 @@
                                      dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
   dbus::MessageReader reader(name_has_owner_response.get());
   bool owned = false;
-  return name_has_owner_response && reader.PopBool(&owned) && owned;
+  if (name_has_owner_response && reader.PopBool(&owned) && owned)
+    return true;
+
+  // If the service currently isn't running, maybe it is activatable.
+  dbus::MethodCall list_activatable_names_call(DBUS_INTERFACE_DBUS,
+                                               kMethodListActivatableNames);
+  std::unique_ptr<dbus::Response> list_activatable_names_response =
+      dbus_proxy->CallMethodAndBlock(&list_activatable_names_call,
+                                     dbus::ObjectProxy::TIMEOUT_USE_DEFAULT);
+  if (list_activatable_names_response) {
+    dbus::MessageReader reader(list_activatable_names_response.get());
+    std::vector<std::string> activatable_names;
+    reader.PopArrayOfStrings(&activatable_names);
+    return base::Contains(activatable_names, kFreedesktopNotificationsName);
+  }
+  return false;
 }
 
 }  // namespace
@@ -441,7 +457,7 @@
       bus_ = base::MakeRefCounted<dbus::Bus>(bus_options);
     }
 
-    if (!CheckNotificationsNameHasOwner(bus_.get())) {
+    if (!CheckNotificationsNameHasOwnerOrIsActivatable(bus_.get())) {
       OnConnectionInitializationFinishedOnTaskRunner(
           ConnectionInitializationStatusCode::
               NATIVE_NOTIFICATIONS_NOT_SUPPORTED);
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc b/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc
index 9f089a98..66cdd8f 100644
--- a/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc
+++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager.cc
@@ -10,7 +10,6 @@
 #include "base/bind.h"
 #include "base/logging.h"
 #include "base/metrics/histogram_functions.h"
-#include "base/metrics/histogram_macros.h"
 #include "base/metrics/histogram_macros_local.h"
 #include "base/rand_util.h"
 #include "base/sequenced_task_runner.h"
@@ -556,34 +555,10 @@
   hints_fetcher_->FetchOptimizationGuideServiceHints(
       top_hosts, std::vector<GURL>{}, registered_optimization_types_,
       optimization_guide::proto::CONTEXT_BATCH_UPDATE,
-      base::BindOnce(&OptimizationGuideHintsManager::OnHintsFetched,
+      base::BindOnce(&OptimizationGuideHintsManager::OnTopHostsHintsFetched,
                      ui_weak_ptr_factory_.GetWeakPtr()));
 }
 
-void OptimizationGuideHintsManager::OnHintsFetched(
-    optimization_guide::proto::RequestContext request_context,
-    optimization_guide::HintsFetcherRequestStatus fetch_status,
-    base::Optional<std::unique_ptr<optimization_guide::proto::GetHintsResponse>>
-        get_hints_response) {
-  switch (request_context) {
-    case optimization_guide::proto::CONTEXT_BATCH_UPDATE:
-      OnTopHostsHintsFetched(std::move(get_hints_response));
-      UMA_HISTOGRAM_ENUMERATION(
-          "OptimizationGuide.HintsFetcher.RequestStatus.BatchUpdate",
-          fetch_status);
-      return;
-    case optimization_guide::proto::CONTEXT_PAGE_NAVIGATION:
-      OnPageNavigationHintsFetched(std::move(get_hints_response));
-      UMA_HISTOGRAM_ENUMERATION(
-          "OptimizationGuide.HintsFetcher.RequestStatus.PageNavigation",
-          fetch_status);
-      return;
-    case optimization_guide::proto::CONTEXT_UNSPECIFIED:
-      NOTREACHED();
-  }
-  NOTREACHED();
-}
-
 void OptimizationGuideHintsManager::OnTopHostsHintsFetched(
     base::Optional<std::unique_ptr<optimization_guide::proto::GetHintsResponse>>
         get_hints_response) {
@@ -751,8 +726,9 @@
       target_hosts_serialized, std::vector<GURL>{},
       registered_optimization_types_,
       optimization_guide::proto::CONTEXT_PAGE_NAVIGATION,
-      base::BindOnce(&OptimizationGuideHintsManager::OnHintsFetched,
-                     ui_weak_ptr_factory_.GetWeakPtr()));
+      base::BindOnce(
+          &OptimizationGuideHintsManager::OnPageNavigationHintsFetched,
+          ui_weak_ptr_factory_.GetWeakPtr()));
 
   for (const auto& host : target_hosts)
     LoadHintForHost(host, base::DoNothing());
@@ -1050,8 +1026,9 @@
   hints_fetcher_->FetchOptimizationGuideServiceHints(
       hosts, urls, registered_optimization_types_,
       optimization_guide::proto::CONTEXT_PAGE_NAVIGATION,
-      base::BindOnce(&OptimizationGuideHintsManager::OnHintsFetched,
-                     ui_weak_ptr_factory_.GetWeakPtr()));
+      base::BindOnce(
+          &OptimizationGuideHintsManager::OnPageNavigationHintsFetched,
+          ui_weak_ptr_factory_.GetWeakPtr()));
 
   if (!hosts.empty() && !urls.empty()) {
     race_navigation_recorder.set_race_attempt_status(
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager.h b/chrome/browser/optimization_guide/optimization_guide_hints_manager.h
index 04b45c1..26d6639 100644
--- a/chrome/browser/optimization_guide/optimization_guide_hints_manager.h
+++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager.h
@@ -207,16 +207,6 @@
   // Service. Used to fetch hints for origins frequently visited by the user.
   void FetchTopHostsHints();
 
-  // Called when the hints have been fetched from the remote Optimization Guide
-  // Service and are ready for parsing or when the fetch was not able to be
-  // completed.
-  void OnHintsFetched(
-      optimization_guide::proto::RequestContext request_context,
-      optimization_guide::HintsFetcherRequestStatus fetch_status,
-      base::Optional<
-          std::unique_ptr<optimization_guide::proto::GetHintsResponse>>
-          get_hints_response);
-
   // Called when the hints for the top hosts have been fetched from the remote
   // Optimization Guide Service and are ready for parsing. This is used when
   // fetching hints in batch mode.
diff --git a/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc b/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc
index f89ff5f..54a48dd 100644
--- a/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc
+++ b/chrome/browser/optimization_guide/optimization_guide_hints_manager_unittest.cc
@@ -189,32 +189,22 @@
       override {
     switch (fetch_state_) {
       case HintsFetcherEndState::kFetchFailed:
-        std::move(hints_fetched_callback)
-            .Run(request_context,
-                 optimization_guide::HintsFetcherRequestStatus::kResponseError,
-                 base::nullopt);
+        std::move(hints_fetched_callback).Run(base::nullopt);
         return false;
       case HintsFetcherEndState::kFetchSuccessWithHostHints:
         hints_fetched_ = true;
         std::move(hints_fetched_callback)
-            .Run(request_context,
-                 optimization_guide::HintsFetcherRequestStatus::kSuccess,
-                 BuildHintsResponse({"host.com"}, {}));
+            .Run(BuildHintsResponse({"host.com"}, {}));
         return true;
       case HintsFetcherEndState::kFetchSuccessWithURLHints:
         hints_fetched_ = true;
         std::move(hints_fetched_callback)
-            .Run(request_context,
-                 optimization_guide::HintsFetcherRequestStatus::kSuccess,
-                 BuildHintsResponse({},
+            .Run(BuildHintsResponse({},
                                     {"https://somedomain.org/news/whatever"}));
         return true;
       case HintsFetcherEndState::kFetchSuccessWithNoHints:
         hints_fetched_ = true;
-        std::move(hints_fetched_callback)
-            .Run(request_context,
-                 optimization_guide::HintsFetcherRequestStatus::kSuccess,
-                 BuildHintsResponse({}, {}));
+        std::move(hints_fetched_callback).Run(BuildHintsResponse({}, {}));
         return true;
     }
     return true;
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
index 7d3a9ad..110fa74 100644
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/ChromePreferenceKeys.java
@@ -574,6 +574,8 @@
     public static final String TAB_ID_MANAGER_NEXT_ID =
             "org.chromium.chrome.browser.tab.TabIdManager.NEXT_ID";
 
+    public static final String TOS_ACKED_ACCOUNTS = "ToS acknowledged accounts";
+
     /**
      * Keys for deferred recording of the outcomes of showing the clear data dialog after
      * Trusted Web Activity client apps are uninstalled or have their data cleared.
@@ -854,6 +856,7 @@
                 SYNC_SESSIONS_UUID,
                 TABBED_ACTIVITY_LAST_BACKGROUNDED_TIME_MS_PREF,
                 TAB_ID_MANAGER_NEXT_ID,
+                TOS_ACKED_ACCOUNTS,
                 TWA_DIALOG_NUMBER_OF_DISMISSALS_ON_CLEAR_DATA,
                 TWA_DIALOG_NUMBER_OF_DISMISSALS_ON_UNINSTALL,
                 TWA_DISCLOSURE_ACCEPTED_PACKAGES,
diff --git a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/SharedPreferencesManager.java b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/SharedPreferencesManager.java
index a895f1a..0329f940 100644
--- a/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/SharedPreferencesManager.java
+++ b/chrome/browser/preferences/android/java/src/org/chromium/chrome/browser/preferences/SharedPreferencesManager.java
@@ -127,6 +127,7 @@
      */
     public void addToStringSet(String key, String value) {
         mKeyChecker.checkIsKeyInUse(key);
+        // Construct a new set so it can be modified safely. See crbug.com/568369.
         Set<String> values = new HashSet<>(
                 ContextUtils.getAppSharedPreferences().getStringSet(key, Collections.emptySet()));
         values.add(value);
@@ -138,6 +139,7 @@
      */
     public void removeFromStringSet(String key, String value) {
         mKeyChecker.checkIsKeyInUse(key);
+        // Construct a new set so it can be modified safely. See crbug.com/568369.
         Set<String> values = new HashSet<>(
                 ContextUtils.getAppSharedPreferences().getStringSet(key, Collections.emptySet()));
         if (values.remove(value)) {
diff --git a/chrome/browser/renderer_context_menu/quick_answers_menu_observer.cc b/chrome/browser/renderer_context_menu/quick_answers_menu_observer.cc
new file mode 100644
index 0000000..2720c70
--- /dev/null
+++ b/chrome/browser/renderer_context_menu/quick_answers_menu_observer.cc
@@ -0,0 +1,134 @@
+// 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/renderer_context_menu/quick_answers_menu_observer.h"
+
+#include <utility>
+
+#include "base/strings/utf_string_conversions.h"
+#include "build/branding_buildflags.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/app/vector_icons/vector_icons.h"
+#include "chrome/browser/profiles/profile.h"
+#include "chromeos/components/quick_answers/quick_answers_model.h"
+#include "components/renderer_context_menu/render_view_context_menu_proxy.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/common/context_menu_params.h"
+
+namespace {
+
+using chromeos::quick_answers::QuickAnswer;
+using chromeos::quick_answers::QuickAnswersClient;
+using chromeos::quick_answers::QuickAnswersRequest;
+
+// TODO(llin): Update the placeholder after finalizing on the design.
+constexpr char kLoadingPlaceholder[] = "Loading...";
+constexpr char kNoResult[] = "See result in Assistant";
+
+}  // namespace
+
+QuickAnswersMenuObserver::QuickAnswersMenuObserver(
+    RenderViewContextMenuProxy* proxy)
+    : proxy_(proxy) {
+  auto* assistant_state = ash::AssistantState::Get();
+  if (assistant_state && proxy_ && proxy_->GetBrowserContext()) {
+    auto* browser_context = proxy_->GetBrowserContext();
+    if (browser_context->IsOffTheRecord())
+      return;
+
+    quick_answers_client_ = std::make_unique<QuickAnswersClient>(
+        content::BrowserContext::GetDefaultStoragePartition(browser_context)
+            ->GetURLLoaderFactoryForBrowserProcess()
+            .get(),
+        assistant_state, this);
+  }
+}
+
+QuickAnswersMenuObserver::~QuickAnswersMenuObserver() = default;
+
+void QuickAnswersMenuObserver::InitMenu(
+    const content::ContextMenuParams& params) {
+  if (!is_eligible_ || !proxy_ || !quick_answers_client_)
+    return;
+
+  if (params.input_field_type ==
+      blink::ContextMenuDataInputFieldType::kPassword)
+    return;
+
+  auto selected_text = base::UTF16ToUTF8(params.selection_text);
+  if (selected_text.empty())
+    return;
+
+    // Add Quick Answer Menu item.
+    // TODO(llin): Update the menu item after finalizing on the design.
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+  proxy_->AddMenuItemWithIcon(IDC_CONTENT_CONTEXT_QUICK_ANSWERS_INLINE_QUERY,
+                              params.selection_text, kAssistantIcon);
+#else
+  proxy_->AddMenuItem(IDC_CONTENT_CONTEXT_QUICK_ANSWERS_INLINE_QUERY,
+                      params.selection_text);
+#endif
+  proxy_->AddMenuItem(IDC_CONTENT_CONTEXT_QUICK_ANSWERS_INLINE_ANSWER,
+                      base::UTF8ToUTF16(kLoadingPlaceholder));
+  proxy_->AddSeparator();
+
+  // Fetch Quick Answer.
+  QuickAnswersRequest request;
+  request.selected_text = selected_text;
+  quick_answers_client_->SendRequest(request);
+}
+
+bool QuickAnswersMenuObserver::IsCommandIdSupported(int command_id) {
+  return (command_id == IDC_CONTENT_CONTEXT_QUICK_ANSWERS_INLINE_QUERY ||
+          command_id == IDC_CONTENT_CONTEXT_QUICK_ANSWERS_INLINE_ANSWER);
+}
+
+bool QuickAnswersMenuObserver::IsCommandIdChecked(int command_id) {
+  return false;
+}
+
+bool QuickAnswersMenuObserver::IsCommandIdEnabled(int command_id) {
+  return command_id == IDC_CONTENT_CONTEXT_QUICK_ANSWERS_INLINE_QUERY;
+}
+
+void QuickAnswersMenuObserver::ExecuteCommand(int command_id) {
+  // TODO(llin): Implements Quick Answers click action.
+}
+
+void QuickAnswersMenuObserver::OnQuickAnswerReceived(
+    std::unique_ptr<QuickAnswer> quick_answer) {
+  if (quick_answer) {
+    proxy_->UpdateMenuItem(
+        IDC_CONTENT_CONTEXT_QUICK_ANSWERS_INLINE_ANSWER,
+        /*enabled=*/false,
+        /*hidden=*/false,
+        /*title=*/
+        base::UTF8ToUTF16(quick_answer->primary_answer.empty()
+                              ? kNoResult
+                              : quick_answer->primary_answer));
+
+    if (!quick_answer->secondary_answer.empty()) {
+      proxy_->UpdateMenuItem(
+          IDC_CONTENT_CONTEXT_QUICK_ANSWERS_INLINE_QUERY,
+          /*enabled=*/true,
+          /*hidden=*/false,
+          /*title=*/base::UTF8ToUTF16(quick_answer->secondary_answer));
+    }
+  } else {
+    proxy_->UpdateMenuItem(IDC_CONTENT_CONTEXT_QUICK_ANSWERS_INLINE_ANSWER,
+                           /*enabled=*/false,
+                           /*hidden=*/false,
+                           /*title=*/base::UTF8ToUTF16(kNoResult));
+  }
+}
+
+void QuickAnswersMenuObserver::OnEligibilityChanged(bool eligible) {
+  is_eligible_ = eligible;
+}
+
+void QuickAnswersMenuObserver::SetQuickAnswerClientForTesting(
+    std::unique_ptr<chromeos::quick_answers::QuickAnswersClient>
+        quick_answers_client) {
+  quick_answers_client_ = std::move(quick_answers_client);
+}
diff --git a/chrome/browser/renderer_context_menu/quick_answers_menu_observer.h b/chrome/browser/renderer_context_menu/quick_answers_menu_observer.h
new file mode 100644
index 0000000..78c03af9
--- /dev/null
+++ b/chrome/browser/renderer_context_menu/quick_answers_menu_observer.h
@@ -0,0 +1,55 @@
+// 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_RENDERER_CONTEXT_MENU_QUICK_ANSWERS_MENU_OBSERVER_H_
+#define CHROME_BROWSER_RENDERER_CONTEXT_MENU_QUICK_ANSWERS_MENU_OBSERVER_H_
+
+#include <memory>
+#include <string>
+
+#include "chromeos/components/quick_answers/quick_answers_client.h"
+#include "components/renderer_context_menu/render_view_context_menu_observer.h"
+
+class RenderViewContextMenuProxy;
+
+// A class that implements the quick answers menu.
+class QuickAnswersMenuObserver
+    : public RenderViewContextMenuObserver,
+      public chromeos::quick_answers::QuickAnswersClient::QuickAnswersDelegate {
+ public:
+  QuickAnswersMenuObserver(const QuickAnswersMenuObserver&) = delete;
+  QuickAnswersMenuObserver& operator=(const QuickAnswersMenuObserver&) = delete;
+
+  explicit QuickAnswersMenuObserver(RenderViewContextMenuProxy* proxy);
+  ~QuickAnswersMenuObserver() override;
+
+  // RenderViewContextMenuObserver implementation.
+  void InitMenu(const content::ContextMenuParams& params) override;
+  bool IsCommandIdSupported(int command_id) override;
+  bool IsCommandIdChecked(int command_id) override;
+  bool IsCommandIdEnabled(int command_id) override;
+  void ExecuteCommand(int command_id) override;
+
+  // QuickAnswersDelegate implementation.
+  void OnQuickAnswerReceived(
+      std::unique_ptr<chromeos::quick_answers::QuickAnswer> answer) override;
+  void OnEligibilityChanged(bool eligible) override;
+
+  void SetQuickAnswerClientForTesting(
+      std::unique_ptr<chromeos::quick_answers::QuickAnswersClient>
+          quick_answers_client);
+
+ private:
+  // The interface to add a context-menu item and update it.
+  RenderViewContextMenuProxy* proxy_;
+
+  std::unique_ptr<chromeos::quick_answers::QuickAnswersClient>
+      quick_answers_client_;
+
+  // Whether the feature is enabled and all eligibility criteria are met (
+  // locale, consents, etc).
+  bool is_eligible_ = false;
+};
+
+#endif  // CHROME_BROWSER_RENDERER_CONTEXT_MENU_QUICK_ANSWERS_MENU_OBSERVER_H_
diff --git a/chrome/browser/renderer_context_menu/quick_answers_menu_observer_browsertest.cc b/chrome/browser/renderer_context_menu/quick_answers_menu_observer_browsertest.cc
new file mode 100644
index 0000000..b196827
--- /dev/null
+++ b/chrome/browser/renderer_context_menu/quick_answers_menu_observer_browsertest.cc
@@ -0,0 +1,255 @@
+// 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/renderer_context_menu/quick_answers_menu_observer.h"
+
+#include "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "chrome/app/chrome_command_ids.h"
+#include "chrome/browser/renderer_context_menu/mock_render_view_context_menu.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chromeos/components/quick_answers/quick_answers_client.h"
+#include "chromeos/components/quick_answers/quick_answers_model.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace {
+
+using chromeos::quick_answers::QuickAnswer;
+using chromeos::quick_answers::QuickAnswersClient;
+using chromeos::quick_answers::QuickAnswersRequest;
+
+using testing::_;
+
+class MockQuickAnswersClient : public QuickAnswersClient {
+ public:
+  MockQuickAnswersClient(network::mojom::URLLoaderFactory* url_loader_factory,
+                         ash::AssistantState* assistant_state,
+                         QuickAnswersMenuObserver* delegate)
+      : QuickAnswersClient(url_loader_factory, assistant_state, delegate) {}
+
+  MockQuickAnswersClient(const MockQuickAnswersClient&) = delete;
+  MockQuickAnswersClient& operator=(const MockQuickAnswersClient&) = delete;
+
+  // QuickAnswersClient::QuickAnswersClient:
+  MOCK_METHOD1(SendRequest, void(const QuickAnswersRequest&));
+};
+
+MATCHER_P(QuickAnswersRequestEqual, quick_answers_request, "") {
+  return (arg.selected_text == quick_answers_request.selected_text);
+}
+
+// A test class for Quick Answers. This test should be a browser test because it
+//// accesses resources.
+class QuickAnswersMenuObserverTest : public InProcessBrowserTest {
+ public:
+  QuickAnswersMenuObserverTest() = default;
+
+  QuickAnswersMenuObserverTest(const QuickAnswersMenuObserverTest&) = delete;
+  QuickAnswersMenuObserverTest& operator=(const QuickAnswersMenuObserverTest&) =
+      delete;
+
+  // InProcessBrowserTest overrides:
+  void SetUpOnMainThread() override {
+    Reset(false);
+    mock_quick_answers_cient_ = std::make_unique<MockQuickAnswersClient>(
+        /*url_loader_factory=*/nullptr,
+        /*assistant_state=*/ash::AssistantState::Get(),
+        /*delegate=*/observer_.get());
+    observer_->OnEligibilityChanged(true);
+  }
+  void TearDownOnMainThread() override {
+    observer_.reset();
+    menu_.reset();
+  }
+
+  void Reset(bool incognito) {
+    observer_.reset();
+    menu_ = std::make_unique<MockRenderViewContextMenu>(incognito);
+    observer_ = std::make_unique<QuickAnswersMenuObserver>(menu_.get());
+    menu_->SetObserver(observer_.get());
+  }
+
+  void InitMenu() {
+    content::ContextMenuParams params;
+    static const base::string16 selected_text = base::ASCIIToUTF16("sel");
+    params.selection_text = selected_text;
+    observer_->InitMenu(params);
+  }
+
+  MockRenderViewContextMenu* menu() { return menu_.get(); }
+  QuickAnswersMenuObserver* observer() { return observer_.get(); }
+
+ protected:
+  void VerifyMenuItems(int index,
+                       int expected_command_id,
+                       const std::string& expected_title,
+                       bool enabled) {
+    MockRenderViewContextMenu::MockMenuItem item;
+    menu()->GetMenuItem(index, &item);
+    EXPECT_EQ(expected_command_id, item.command_id);
+    EXPECT_EQ(base::UTF8ToUTF16(expected_title), item.title);
+    EXPECT_EQ(enabled, item.enabled);
+    EXPECT_FALSE(item.hidden);
+  }
+
+  void MockQuickAnswerClient() {
+    std::unique_ptr<QuickAnswersRequest> expected_quick_answers_request =
+        std::make_unique<QuickAnswersRequest>();
+    expected_quick_answers_request->selected_text = "sel";
+    EXPECT_CALL(
+        *mock_quick_answers_cient_,
+        SendRequest(QuickAnswersRequestEqual(*expected_quick_answers_request)))
+        .Times(1);
+    observer_->SetQuickAnswerClientForTesting(
+        std::move(mock_quick_answers_cient_));
+  }
+
+  std::unique_ptr<QuickAnswersMenuObserver> observer_;
+  std::unique_ptr<MockQuickAnswersClient> mock_quick_answers_cient_;
+
+  std::unique_ptr<MockRenderViewContextMenu> menu_;
+};
+
+}  // namespace
+
+IN_PROC_BROWSER_TEST_F(QuickAnswersMenuObserverTest, PlaceHolderMenuItems) {
+  MockQuickAnswerClient();
+  InitMenu();
+
+  // Shows quick answers loading state.
+  ASSERT_EQ(3u, menu()->GetMenuSize());
+
+  // Verify the query menu item.
+  VerifyMenuItems(
+      /*index=*/0,
+      /*command_id=*/IDC_CONTENT_CONTEXT_QUICK_ANSWERS_INLINE_QUERY,
+      /*expected_title=*/"sel",
+      /*enabled=*/true);
+  // Verify the answer menu item.
+  VerifyMenuItems(
+      /*index=*/1,
+      /*command_id=*/IDC_CONTENT_CONTEXT_QUICK_ANSWERS_INLINE_ANSWER,
+      /*expected_title=*/"Loading...",
+      /*enabled=*/false);
+}
+
+IN_PROC_BROWSER_TEST_F(QuickAnswersMenuObserverTest, PrimaryAnswerOnly) {
+  MockQuickAnswerClient();
+  InitMenu();
+
+  std::unique_ptr<QuickAnswer> quick_answer = std::make_unique<QuickAnswer>();
+  quick_answer->primary_answer = "primary answer";
+  observer_->OnQuickAnswerReceived(std::move(quick_answer));
+
+  // Verify that quick answer menu items is showing.
+  ASSERT_EQ(3u, menu()->GetMenuSize());
+
+  // Verify the query menu item.
+  VerifyMenuItems(
+      /*index=*/0,
+      /*command_id=*/IDC_CONTENT_CONTEXT_QUICK_ANSWERS_INLINE_QUERY,
+      /*expected_title=*/"sel",
+      /*enabled=*/true);
+
+  // Verify the answer menu item.
+  VerifyMenuItems(
+      /*index=*/1,
+      /*command_id=*/IDC_CONTENT_CONTEXT_QUICK_ANSWERS_INLINE_ANSWER,
+      /*expected_title=*/"primary answer",
+      /*enabled=*/false);
+}
+
+IN_PROC_BROWSER_TEST_F(QuickAnswersMenuObserverTest, SecondaryAnswerOnly) {
+  MockQuickAnswerClient();
+  InitMenu();
+
+  std::unique_ptr<QuickAnswer> quick_answer = std::make_unique<QuickAnswer>();
+  quick_answer->secondary_answer = "secondary answer";
+  observer_->OnQuickAnswerReceived(std::move(quick_answer));
+
+  // Verify that quick answer menu items is showing.
+  ASSERT_EQ(3u, menu()->GetMenuSize());
+
+  // Verify the query menu item.
+  VerifyMenuItems(
+      /*index=*/0,
+      /*command_id=*/IDC_CONTENT_CONTEXT_QUICK_ANSWERS_INLINE_QUERY,
+      /*expected_title=*/"secondary answer",
+      /*enabled=*/true);
+
+  // Verify the answer menu item.
+  VerifyMenuItems(
+      /*index=*/1,
+      /*command_id=*/IDC_CONTENT_CONTEXT_QUICK_ANSWERS_INLINE_ANSWER,
+      /*expected_title=*/"See result in Assistant",
+      /*enabled=*/false);
+}
+
+IN_PROC_BROWSER_TEST_F(QuickAnswersMenuObserverTest,
+                       PrimaryAndSecondaryAnswer) {
+  MockQuickAnswerClient();
+  InitMenu();
+
+  std::unique_ptr<QuickAnswer> quick_answer = std::make_unique<QuickAnswer>();
+  quick_answer->primary_answer = "primary answer";
+  quick_answer->secondary_answer = "secondary answer";
+  observer_->OnQuickAnswerReceived(std::move(quick_answer));
+
+  // Verify that quick answer menu items is showing.
+  ASSERT_EQ(3u, menu()->GetMenuSize());
+
+  // Verify the query menu item.
+  VerifyMenuItems(
+      /*index=*/0,
+      /*command_id=*/IDC_CONTENT_CONTEXT_QUICK_ANSWERS_INLINE_QUERY,
+      /*expected_title=*/"secondary answer",
+      /*enabled=*/true);
+
+  // Verify the answer menu item.
+  VerifyMenuItems(
+      /*index=*/1,
+      /*command_id=*/IDC_CONTENT_CONTEXT_QUICK_ANSWERS_INLINE_ANSWER,
+      /*expected_title=*/"primary answer",
+      /*enabled=*/false);
+}
+
+IN_PROC_BROWSER_TEST_F(QuickAnswersMenuObserverTest, NoAnswer) {
+  MockQuickAnswerClient();
+  InitMenu();
+
+  observer_->OnQuickAnswerReceived(nullptr);
+
+  // Verify that quick answer menu items is showing.
+  ASSERT_EQ(3u, menu()->GetMenuSize());
+
+  // Verify the query menu item.
+  VerifyMenuItems(
+      /*index=*/0,
+      /*command_id=*/IDC_CONTENT_CONTEXT_QUICK_ANSWERS_INLINE_QUERY,
+      /*expected_title=*/"sel",
+      /*enabled=*/true);
+
+  // Verify the answer menu item.
+  VerifyMenuItems(
+      /*index=*/1,
+      /*command_id=*/IDC_CONTENT_CONTEXT_QUICK_ANSWERS_INLINE_ANSWER,
+      /*expected_title=*/"See result in Assistant",
+      /*enabled=*/false);
+}
+
+IN_PROC_BROWSER_TEST_F(QuickAnswersMenuObserverTest, FeatureIneligible) {
+  observer_->OnEligibilityChanged(false);
+
+  // Verify that quick answer client is not called to fetch result.
+  EXPECT_CALL(*mock_quick_answers_cient_, SendRequest(testing::_)).Times(0);
+  observer_->SetQuickAnswerClientForTesting(
+      std::move(mock_quick_answers_cient_));
+
+  InitMenu();
+
+  // Verify that no Quick Answer menu items shown.
+  ASSERT_EQ(0u, menu()->GetMenuSize());
+}
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.cc b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
index 292a302..e70bae63 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.cc
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.cc
@@ -198,6 +198,7 @@
 #include "chrome/browser/chromeos/arc/arc_util.h"
 #include "chrome/browser/chromeos/arc/intent_helper/open_with_menu.h"
 #include "chrome/browser/chromeos/arc/intent_helper/start_smart_selection_action_menu.h"
+#include "chrome/browser/renderer_context_menu/quick_answers_menu_observer.h"
 #endif
 
 using base::UserMetricsAction;
@@ -804,6 +805,8 @@
 void RenderViewContextMenu::InitMenu() {
   RenderViewContextMenuBase::InitMenu();
 
+  AppendQuickAnswersItems();
+
   if (content_type_->SupportsGroup(
           ContextMenuContentType::ITEM_GROUP_PASSWORD)) {
     AppendPasswordItems();
@@ -1331,6 +1334,18 @@
 #endif
 }
 
+void RenderViewContextMenu::AppendQuickAnswersItems() {
+#if defined(OS_CHROMEOS)
+  if (!quick_answers_menu_observer_) {
+    quick_answers_menu_observer_ =
+        std::make_unique<QuickAnswersMenuObserver>(this);
+  }
+
+  observers_.AddObserver(quick_answers_menu_observer_.get());
+  quick_answers_menu_observer_->InitMenu(params_);
+#endif
+}
+
 void RenderViewContextMenu::AppendSmartSelectionActionItems() {
 #if defined(OS_CHROMEOS)
   start_smart_selection_action_menu_observer_ =
diff --git a/chrome/browser/renderer_context_menu/render_view_context_menu.h b/chrome/browser/renderer_context_menu/render_view_context_menu.h
index d5195d4..da5e511f 100644
--- a/chrome/browser/renderer_context_menu/render_view_context_menu.h
+++ b/chrome/browser/renderer_context_menu/render_view_context_menu.h
@@ -37,6 +37,7 @@
 class ClickToCallContextMenuObserver;
 class PrintPreviewContextMenuObserver;
 class Profile;
+class QuickAnswersMenuObserver;
 class SharedClipboardContextMenuObserver;
 class SpellingMenuObserver;
 class SpellingOptionsSubMenuObserver;
@@ -159,6 +160,7 @@
   void AppendOpenWithLinkItems();
   void AppendSmartSelectionActionItems();
   void AppendOpenInBookmarkAppLinkItems();
+  void AppendQuickAnswersItems();
   void AppendImageItems();
   void AppendAudioItems();
   void AppendCanvasItems();
@@ -275,6 +277,7 @@
   // An observer that handles smart text selection action items.
   std::unique_ptr<RenderViewContextMenuObserver>
       start_smart_selection_action_menu_observer_;
+  std::unique_ptr<QuickAnswersMenuObserver> quick_answers_menu_observer_;
 #endif
 
 #if BUILDFLAG(ENABLE_PRINT_PREVIEW)
diff --git a/chrome/browser/resources/chromeos/login/sync_consent.css b/chrome/browser/resources/chromeos/login/sync_consent.css
index 034b2431..c73b1b2 100644
--- a/chrome/browser/resources/chromeos/login/sync_consent.css
+++ b/chrome/browser/resources/chromeos/login/sync_consent.css
@@ -32,3 +32,19 @@
   --cr-checkbox-label-padding-start: 12px;
 }
 
+/* Styles used with SplitSettingsSync. */
+
+#osSyncConsentFooter {
+  border-bottom: solid 1px var(--google-grey-300);
+  border-top: solid 1px var(--google-grey-300);
+  padding: 16px 0;
+}
+
+#osSyncConsentToggleName {
+  font-weight: 500;
+  margin-bottom: 4px;
+}
+
+#osSyncConsentToggleDescription {
+  color: var(--google-grey-700);
+}
diff --git a/chrome/browser/resources/chromeos/login/sync_consent.html b/chrome/browser/resources/chromeos/login/sync_consent.html
index 095d8d62..3760c05 100644
--- a/chrome/browser/resources/chromeos/login/sync_consent.html
+++ b/chrome/browser/resources/chromeos/login/sync_consent.html
@@ -29,8 +29,7 @@
               src1x="chrome://oobe/logo_24px-1x.svg"
               src2x="chrome://oobe/logo_24px-2x.svg">
           </hd-iron-icon>
-          <div class="overview-list-item-text flex layout vertical
-              center-justified">
+          <div class="flex layout vertical center-justified">
             <div role="heading" aria-level="2" class="overview-list-item-title"
               consent-description>
                 [[i18nDynamic(locale, 'syncConsentScreenChromeSyncName')]]
@@ -44,8 +43,7 @@
           <hd-iron-icon class="overview-list-item-icon"
               icon1x="sync-consent-32:googleg" icon2x="sync-consent-64:googleg">
           </hd-iron-icon>
-          <div class="overview-list-item-text flex layout vertical
-              center-justified">
+          <div class="flex layout vertical center-justified">
             <div role ="heading" aria-level="2" class="overview-list-item-title"
               consent-description>
                 [[i18nDynamic(locale,
@@ -82,19 +80,18 @@
         [[i18nDynamic(locale, 'osSyncConsentTitle')]]
       </h1>
       <div slot="footer" class="layout vertical">
-        <div class="overview-list-item flex layout horizontal center">
-          <div class="overview-list-item-text flex layout vertical
-              center-justified">
-            <div role="heading" aria-level="2" class="overview-list-item-title"
-                id="enableOsSyncLabel" consent-description>
+        <div id="osSyncConsentFooter" class="flex layout horizontal center">
+          <div class="flex layout vertical center-justified">
+            <div role="heading" aria-level="2"  id="osSyncConsentToggleName"
+                consent-description>
               [[i18nDynamic(locale, 'osSyncConsentToggleName')]]
             </div>
-            <div class="overview-list-item-description" consent-description>
+            <div id="osSyncConsentToggleDescription" consent-description>
               [[i18nDynamic(locale, 'osSyncConsentToggleDescription')]]
             </div>
           </div>
           <cr-toggle id="enableOsSyncToggle" checked
-              aria-labelledby="enableOsSyncLabel">
+              aria-labelledby="osSyncConsentToggleName">
           </cr-toggle>
         </div>
       </div>
diff --git a/chrome/browser/resources/chromeos/smb_shares/OWNERS b/chrome/browser/resources/chromeos/smb_shares/OWNERS
index 704b95c8..0da0ab6 100644
--- a/chrome/browser/resources/chromeos/smb_shares/OWNERS
+++ b/chrome/browser/resources/chromeos/smb_shares/OWNERS
@@ -1 +1,3 @@
-khorimoto@chromium.org
\ No newline at end of file
+amistry@chromium.org
+
+# COMPONENT: Enterprise>ActiveDirectory
\ No newline at end of file
diff --git a/chrome/browser/resources/downloads/OWNERS b/chrome/browser/resources/downloads/OWNERS
index 455bfb5..cb00587 100644
--- a/chrome/browser/resources/downloads/OWNERS
+++ b/chrome/browser/resources/downloads/OWNERS
@@ -1,3 +1 @@
-dbeam@chromium.org
-
 # COMPONENT: UI>Browser>Downloads
diff --git a/chrome/browser/resources/history/OWNERS b/chrome/browser/resources/history/OWNERS
index 5152930..5e21905 100644
--- a/chrome/browser/resources/history/OWNERS
+++ b/chrome/browser/resources/history/OWNERS
@@ -1,4 +1,3 @@
 calamity@chromium.org
-dbeam@chromium.org
 
 # COMPONENT: UI>Browser>History
diff --git a/chrome/browser/resources/local_ntp/local_ntp.css b/chrome/browser/resources/local_ntp/local_ntp.css
index 74aab7e1..e3d9220 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.css
+++ b/chrome/browser/resources/local_ntp/local_ntp.css
@@ -227,6 +227,20 @@
 #realbox-icon {
   background-position: center center;
   background-repeat: no-repeat;
+  bottom: 0;
+  left: 16px;
+  margin: auto;
+  position: absolute;
+  top: 0;
+  width: 24px;
+}
+
+[dir=rtl] #realbox-icon {
+  left: auto;
+  right: 16px;
+}
+
+#realbox-icon.load-favicon {
   background-size: 24px;
 }
 
@@ -500,8 +514,7 @@
   right: auto;
 }
 
-#realbox-input-wrapper > :-webkit-any(.google-g-icon, .microphone-icon,
-                                      .search-icon) {
+#realbox-input-wrapper > :-webkit-any(#realbox-icon, .microphone-icon) {
   z-index: 3;
 }
 
diff --git a/chrome/browser/resources/local_ntp/local_ntp.html b/chrome/browser/resources/local_ntp/local_ntp.html
index 3c24062..e09bb54f 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.html
+++ b/chrome/browser/resources/local_ntp/local_ntp.html
@@ -78,7 +78,8 @@
 
     <div id="realbox-container" $i18n{hiddenIfRealboxDisabled}>
       <div id="realbox-input-wrapper">
-        <div id="realbox-icon" class="$i18n{realboxIconClass}"></div>
+        <div id="realbox-icon" class="$i18n{realboxIconClass}"
+            data-realbox-icon-class="$i18n{realboxIconClass}"></div>
         <input id="realbox" type="search" autocomplete="off" spellcheck="false"
             aria-live="polite" autofocus>
         <button id="realbox-microphone" class="microphone-icon" hidden></button>
diff --git a/chrome/browser/resources/local_ntp/local_ntp.js b/chrome/browser/resources/local_ntp/local_ntp.js
index bde8e39..0e9acb0 100644
--- a/chrome/browser/resources/local_ntp/local_ntp.js
+++ b/chrome/browser/resources/local_ntp/local_ntp.js
@@ -91,6 +91,7 @@
   IMAGE_CONTAINER: 'image-container',
   INITED: 'inited',  // Reveals the <body> once init() is done.
   LEFT_ALIGN_ATTRIBUTION: 'left-align-attribution',
+  LOAD_FAVICON: 'load-favicon',
   // The image next to a realbox match.
   MATCH_IMAGE: 'match-image',
   // Vertically centers the most visited section for a non-Google provided page.
@@ -724,7 +725,7 @@
   // TODO(crbug.com/997229): use chrome://favicon/<url> when perms allow.
   const iconUrl = new URL('chrome-search://ntpicon/');
   iconUrl.searchParams.set('show_fallback_monogram', 'false');
-  iconUrl.searchParams.set('size', '24@' + window.devicePixelRatio + 'x');
+  iconUrl.searchParams.set('size', '32@' + window.devicePixelRatio + 'x');
   // The fallback color must match that of .clock-icon and .search-icon
   iconUrl.searchParams.set(
       'color',
@@ -2118,13 +2119,19 @@
 
 /** @param {!AutocompleteMatch|undefined} match */
 function setRealboxIcon(match) {
-  const showIcon = match && !match.isSearchType;
+  const loadFavicon = match && !match.isSearchType;
 
   const realboxIcon = $(IDS.REALBOX_ICON);
-  realboxIcon.style.webkitMask = showIcon ? 'none' : '';
-  realboxIcon.style.backgroundColor = showIcon ? 'transparent' : '';
+  realboxIcon.style.webkitMask = loadFavicon ? 'none' : '';
+  realboxIcon.style.backgroundColor = loadFavicon ? 'transparent' : '';
   realboxIcon.style.backgroundImage =
-      showIcon ? `url(${getIconUrl(match.destinationUrl)})` : '';
+      loadFavicon ? `url(${getIconUrl(match.destinationUrl)})` : '';
+
+  const historical = match && SEARCH_HISTORY_MATCH_TYPES.includes(match.type);
+  realboxIcon.className = loadFavicon ?
+      CLASSES.LOAD_FAVICON :
+      (historical ? CLASSES.CLOCK_ICON :
+                    realboxIcon.dataset['realboxIconClass']);
 }
 
 /** @param {boolean} visible */
diff --git a/chrome/browser/resources/settings/OWNERS b/chrome/browser/resources/settings/OWNERS
index b887eda..81a6dc6 100644
--- a/chrome/browser/resources/settings/OWNERS
+++ b/chrome/browser/resources/settings/OWNERS
@@ -1,4 +1,3 @@
-dbeam@chromium.org
 dpapad@chromium.org
 dschuyler@chromium.org
 hcarmona@chromium.org
diff --git a/chrome/browser/resources/settings/people_page/people_page.html b/chrome/browser/resources/settings/people_page/people_page.html
index bc248ce..d143e53 100644
--- a/chrome/browser/resources/settings/people_page/people_page.html
+++ b/chrome/browser/resources/settings/people_page/people_page.html
@@ -3,6 +3,7 @@
 <link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
 <link rel="import" href="chrome://resources/cr_elements/cr_link_row/cr_link_row.html">
+<link rel="import" href="chrome://resources/cr_elements/cr_toast/cr_toast.html">
 <link rel="import" href="chrome://resources/cr_elements/icons.html">
 <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_indicator.html">
 <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
@@ -32,7 +33,6 @@
 <link rel="import" href="chrome://resources/cr_elements/chromeos/cr_picture/cr_png_behavior.html">
 </if>
 <if expr="not chromeos">
-<link rel="import" href="chrome://resources/cr_elements/cr_toast/cr_toast.html">
 <link rel="import" href="import_data_dialog.html">
 <link rel="import" href="manage_profile.html">
 </if>
@@ -76,7 +76,6 @@
         width: 40px;
       }
 
-<if expr="not chromeos">
       #toast {
         left: 0;
         z-index: 1;
@@ -98,12 +97,10 @@
         font-size: 1.1rem;
         line-height: 1.625rem;
       }
-</if>
     </style>
     <settings-animated-pages id="pages" section="people"
         focus-config="[[focusConfig_]]">
       <div route-path="default">
-<if expr="not chromeos">
         <template is="dom-if" if="[[shouldShowSyncAccountControl_(
             syncStatus.syncSystemEnabled, syncStatus.signinAllowed)]]">
           <settings-sync-account-control
@@ -117,8 +114,8 @@
                   "$i18n{peopleSignInPromptSecondaryWithNoAccount}">
           </settings-sync-account-control>
         </template>
-        <template is="dom-if" if="[[!diceEnabled_]]">
-</if>
+        <template is="dom-if" if="[[shouldShowProfile_(
+            syncStatus.syncSystemEnabled, syncStatus.signinAllowed)]]" restamp>
           <div id="picture-subpage-trigger" class="settings-box first two-line">
             <template is="dom-if" if="[[syncStatus]]">
               <div id="profile-icon" on-click="onProfileTap_"
@@ -151,6 +148,7 @@
                     aria-describedby="profile-name"></cr-icon-button>
 </if>
               </div>
+<!-- Chrome OS is always signed-in and does not show a sign-out button. -->
 <if expr="not chromeos">
               <template is="dom-if" if="[[showSignin_(syncStatus)]]">
                 <div class="separator"></div>
@@ -169,14 +167,12 @@
 </if>
             </template>
           </div>
-<if expr="not chromeos">
-        </template> <!-- if="[[!diceEnabled_]]" -->
-</if>
+        </template> <!-- if="[[shouldShowProfile_()]]" -->
 
-        <template is="dom-if" if="[[!syncStatus.signedIn]]">
+<!-- Chrome OS uses settings-sync-account-control for sync promos. -->
 <if expr="not chromeos">
+        <template is="dom-if" if="[[!syncStatus.signedIn]]">
           <template is="dom-if" if="[[!diceEnabled_]]">
-</if>
             <div class="settings-box two-line" id="sync-overview"
                 hidden="[[!syncStatus.signinAllowed]]">
               <div class="start settings-box-text">
@@ -186,10 +182,9 @@
                 </a>
               </div>
             </div>
-<if expr="not chromeos">
           </template> <!-- if="[[!diceEnabled_]]" -->
-</if>
         </template>
+</if>
 
         <cr-link-row id="sync-setup"
             label="$i18n{syncAndNonPersonalizedServices}"
@@ -230,9 +225,6 @@
             page-title="$i18n{syncPageTitle}"
             learn-more-url="$i18n{syncAndGoogleServicesLearnMoreURL}">
           <settings-sync-page
-<if expr="not chromeos">
-              dice-enabled="[[diceEnabled_]]"
-</if>
               sync-status="[[syncStatus]]" prefs="{{prefs}}"
               page-visibility="[[pageVisibility.privacy]]">
           </settings-sync-page>
@@ -272,11 +264,9 @@
           on-close="onImportDataDialogClosed_">
       </settings-import-data-dialog>
     </template>
-<if expr="not chromeos">
     <cr-toast duration="3000" id="toast">
       <span>$i18n{syncSettingsSavedToast}</span>
     </cr-toast>
-</if>
   </template>
   <script src="people_page.js"></script>
 </dom-module>
diff --git a/chrome/browser/resources/settings/people_page/people_page.js b/chrome/browser/resources/settings/people_page/people_page.js
index 4d5bd65..979bb9e8 100644
--- a/chrome/browser/resources/settings/people_page/people_page.js
+++ b/chrome/browser/resources/settings/people_page/people_page.js
@@ -25,6 +25,7 @@
       notify: true,
     },
 
+    // Chrome OS does not support DICE.
     // <if expr="not chromeos">
     /**
      * This flag is used to conditionally show a set of new sign-in UIs to the
@@ -278,13 +279,7 @@
 
     this.syncStatus = syncStatus;
 
-    if (
-        shouldRecordSigninImpression
-        // <if expr="not chromeos">
-        // Sync account control is not shown on Chrome OS.
-        && !this.shouldShowSyncAccountControl_()
-        // </if>
-    ) {
+    if (shouldRecordSigninImpression && !this.shouldShowSyncAccountControl_()) {
       // SyncAccountControl records the impressions user actions.
       chrome.metricsPrivate.recordUserAction('Signin_Impression_FromSettings');
     }
@@ -334,10 +329,6 @@
     }
     // </if>
 
-    // <if expr="chromeos">
-    cr.ui.focusWithoutInk(assert(this.$$('#disconnectButton')));
-    // </if>
-
     if (settings.Router.getInstance().getCurrentRoute() ==
         settings.routes.SIGN_OUT) {
       settings.Router.getInstance().navigateToPreviousRoute();
@@ -366,6 +357,7 @@
     settings.Router.getInstance().navigateToPreviousRoute();
     cr.ui.focusWithoutInk(assert(this.$.importDataDialogTrigger));
   },
+  // </if>
 
   /**
    * Open URL for managing your Google Account.
@@ -385,11 +377,30 @@
     if (this.syncStatus == undefined) {
       return false;
     }
-
+    // <if expr="chromeos">
+    if (!loadTimeData.getBoolean('splitSettingsSyncEnabled')) {
+      return false;
+    }
+    // </if>
     return !!this.syncStatus.syncSystemEnabled &&
         !!this.syncStatus.signinAllowed;
   },
-  // </if>
+
+  /**
+   * @return {boolean} Whether to show the profile row and associated controls.
+   * @private
+   */
+  shouldShowProfile_() {
+    // Closure compiler doesn't understand <if> so use a variable.
+    let show = false;
+    // <if expr="chromeos">
+    show = !this.shouldShowSyncAccountControl_();
+    // </if>
+    // <if expr="not chromeos">
+    show = !this.diceEnabled_;
+    // </if>
+    return show;
+  },
 
   /**
    * @param {string} iconUrl
diff --git a/chrome/browser/resources/settings/people_page/sync_page.js b/chrome/browser/resources/settings/people_page/sync_page.js
index 39412e4..35954f1a 100644
--- a/chrome/browser/resources/settings/people_page/sync_page.js
+++ b/chrome/browser/resources/settings/people_page/sync_page.js
@@ -147,10 +147,6 @@
           'syncPrefs.trustedVaultKeysRequired)',
     },
 
-    // <if expr="not chromeos">
-    diceEnabled: Boolean,
-    // </if>
-
     /** @private */
     showSetupCancelDialog_: {
       type: Boolean,
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
index 5ff5fb7..5093a5e 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
@@ -561,11 +561,11 @@
 }
 
 TEST_F(ChromePasswordProtectionServiceTest, VerifyCanSendSamplePing) {
-  // If experiment is not enabled, do not send ping.
+  // Experiment is on by default.
   service_->ConfigService(/*is_incognito=*/false,
                           /*is_extended_reporting=*/true);
   service_->set_bypass_probability_for_tests(true);
-  EXPECT_FALSE(service_->CanSendSamplePing());
+  EXPECT_TRUE(service_->CanSendSamplePing());
 
   {
     base::test::ScopedFeatureList feature_list;
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc b/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc
index f7e3fbd..5b7fa064 100644
--- a/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc
+++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request.cc
@@ -143,7 +143,7 @@
   return IsSupportedDownload(*item_, item_->GetTargetFilePath(), reason, type);
 }
 
-content::BrowserContext* CheckClientDownloadRequest::GetBrowserContext() {
+content::BrowserContext* CheckClientDownloadRequest::GetBrowserContext() const {
   return content::DownloadItemUtils::GetBrowserContext(item_);
 }
 
@@ -244,6 +244,17 @@
   item_->RemoveObserver(this);
 }
 
+bool CheckClientDownloadRequest::ShouldPromptForDeepScanning(
+    DownloadCheckResultReason reason) const {
+  if (reason != REASON_DOWNLOAD_UNCOMMON)
+    return false;
+
+  Profile* profile = Profile::FromBrowserContext(GetBrowserContext());
+  return base::FeatureList::IsEnabled(kPromptAppForDeepScanning) &&
+         AdvancedProtectionStatusManagerFactory::GetForProfile(profile)
+             ->IsUnderAdvancedProtection();
+}
+
 bool CheckClientDownloadRequest::ShouldUploadForDlpScan() {
   if (!base::FeatureList::IsEnabled(kContentComplianceEnabled))
     return false;
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request.h b/chrome/browser/safe_browsing/download_protection/check_client_download_request.h
index 33062a9..ca0528f 100644
--- a/chrome/browser/safe_browsing/download_protection/check_client_download_request.h
+++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request.h
@@ -50,7 +50,7 @@
   // CheckClientDownloadRequestBase overrides:
   bool IsSupportedDownload(DownloadCheckResultReason* reason,
                            ClientDownloadRequest::DownloadType* type) override;
-  content::BrowserContext* GetBrowserContext() override;
+  content::BrowserContext* GetBrowserContext() const override;
   bool IsCancelled() override;
   void PopulateRequest(ClientDownloadRequest* request) override;
   base::WeakPtr<CheckClientDownloadRequestBase> GetWeakPtr() override;
@@ -71,6 +71,11 @@
   void NotifyRequestFinished(DownloadCheckResult result,
                              DownloadCheckResultReason reason) override;
 
+  // Called when finishing the download, to decide whether to prompt the user
+  // for deep scanning or not.
+  bool ShouldPromptForDeepScanning(
+      DownloadCheckResultReason reason) const override;
+
   // Returns true when the file should be uploaded for a DLP compliance scan.
   // This consults the CheckContentCompliance enterprise policy.
   bool ShouldUploadForDlpScan();
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc
index 77c015d8..25855e4 100644
--- a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc
+++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.cc
@@ -229,10 +229,11 @@
       UploadBinary();
       did_upload_binary = true;
     }
+  } else if (ShouldPromptForDeepScanning(reason)) {
+    result = DownloadCheckResult::PROMPT_FOR_SCANNING;
+    reason = DownloadCheckResultReason::REASON_ADVANCED_PROTECTION_PROMPT;
   }
 
-  DVLOG(2) << "SafeBrowsing download verdict for: " << source_url_
-           << " verdict:" << reason << " result:" << static_cast<int>(result);
   UMA_HISTOGRAM_ENUMERATION("SBClientDownload.CheckDownloadStats", reason,
                             REASON_MAX);
 
diff --git a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.h b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.h
index 7d67d0b..67eeb19fe7 100644
--- a/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.h
+++ b/chrome/browser/safe_browsing/download_protection/check_client_download_request_base.h
@@ -102,7 +102,7 @@
   virtual bool IsSupportedDownload(
       DownloadCheckResultReason* reason,
       ClientDownloadRequest::DownloadType* type) = 0;
-  virtual content::BrowserContext* GetBrowserContext() = 0;
+  virtual content::BrowserContext* GetBrowserContext() const = 0;
   virtual bool IsCancelled() = 0;
   virtual base::WeakPtr<CheckClientDownloadRequestBase> GetWeakPtr() = 0;
 
@@ -143,6 +143,11 @@
   virtual void NotifyRequestFinished(DownloadCheckResult result,
                                      DownloadCheckResultReason reason) = 0;
 
+  // Called when finishing the download, to decide whether to prompt the user
+  // for deep scanning or not.
+  virtual bool ShouldPromptForDeepScanning(
+      DownloadCheckResultReason reason) const = 0;
+
   // Source URL being downloaded from. This shuold always be set, but could be
   // for example an artificial blob: URL if there is no source URL.
   const GURL source_url_;
diff --git a/chrome/browser/safe_browsing/download_protection/check_native_file_system_write_request.cc b/chrome/browser/safe_browsing/download_protection/check_native_file_system_write_request.cc
index 5967ded..37004a5a 100644
--- a/chrome/browser/safe_browsing/download_protection/check_native_file_system_write_request.cc
+++ b/chrome/browser/safe_browsing/download_protection/check_native_file_system_write_request.cc
@@ -92,8 +92,8 @@
   return true;
 }
 
-content::BrowserContext*
-CheckNativeFileSystemWriteRequest::GetBrowserContext() {
+content::BrowserContext* CheckNativeFileSystemWriteRequest::GetBrowserContext()
+    const {
   return item_->browser_context;
 }
 
@@ -159,6 +159,11 @@
 
 void CheckNativeFileSystemWriteRequest::UploadBinary() {}
 
+bool CheckNativeFileSystemWriteRequest::ShouldPromptForDeepScanning(
+    DownloadCheckResultReason reason) const {
+  return false;
+}
+
 void CheckNativeFileSystemWriteRequest::NotifyRequestFinished(
     DownloadCheckResult result,
     DownloadCheckResultReason reason) {
diff --git a/chrome/browser/safe_browsing/download_protection/check_native_file_system_write_request.h b/chrome/browser/safe_browsing/download_protection/check_native_file_system_write_request.h
index cad4e90c..9c14e2f 100644
--- a/chrome/browser/safe_browsing/download_protection/check_native_file_system_write_request.h
+++ b/chrome/browser/safe_browsing/download_protection/check_native_file_system_write_request.h
@@ -38,7 +38,7 @@
   // CheckClientDownloadRequestBase overrides:
   bool IsSupportedDownload(DownloadCheckResultReason* reason,
                            ClientDownloadRequest::DownloadType* type) override;
-  content::BrowserContext* GetBrowserContext() override;
+  content::BrowserContext* GetBrowserContext() const override;
   bool IsCancelled() override;
   void PopulateRequest(ClientDownloadRequest* request) override;
   base::WeakPtr<CheckClientDownloadRequestBase> GetWeakPtr() override;
@@ -51,6 +51,8 @@
                                   const std::string& response_body) override;
   bool ShouldUploadBinary(DownloadCheckResultReason reason) override;
   void UploadBinary() override;
+  bool ShouldPromptForDeepScanning(
+      DownloadCheckResultReason reason) const override;
   void NotifyRequestFinished(DownloadCheckResult result,
                              DownloadCheckResultReason reason) override;
 
diff --git a/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc b/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc
index 56b37b5..fbfc770 100644
--- a/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc
+++ b/chrome/browser/safe_browsing/download_protection/deep_scanning_request.cc
@@ -4,6 +4,9 @@
 
 #include "chrome/browser/safe_browsing/download_protection/deep_scanning_request.h"
 
+#include "base/bind.h"
+#include "base/bind_helpers.h"
+#include "base/callback_forward.h"
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router.h"
@@ -13,6 +16,9 @@
 #include "chrome/browser/safe_browsing/download_protection/download_item_request.h"
 #include "chrome/browser/safe_browsing/download_protection/download_protection_service.h"
 #include "chrome/browser/safe_browsing/download_protection/download_protection_util.h"
+#include "chrome/browser/ui/browser.h"
+#include "chrome/browser/ui/browser_finder.h"
+#include "chrome/browser/ui/views/safe_browsing/deep_scanning_failure_modal_dialog.h"
 #include "components/download/public/common/download_item.h"
 #include "components/policy/core/browser/url_util.h"
 #include "components/policy/core/common/cloud/dm_token.h"
@@ -195,7 +201,7 @@
       /*response=*/response);
   Profile* profile = Profile::FromBrowserContext(
       content::DownloadItemUtils::GetBrowserContext(item_));
-  if (profile) {
+  if (profile && trigger_ == DeepScanTrigger::TRIGGER_POLICY) {
     std::string raw_digest_sha256 = item_->GetHash();
     MaybeReportDeepScanningVerdict(
         profile, item_->GetURL(), item_->GetTargetFilePath().AsUTF8Unsafe(),
@@ -208,6 +214,16 @@
   DownloadCheckResult download_result = DownloadCheckResult::UNKNOWN;
   if (result == BinaryUploadService::Result::SUCCESS) {
     DeepScanningClientResponseToDownloadCheckResult(response, &download_result);
+  } else if (trigger_ == DeepScanTrigger::TRIGGER_APP_PROMPT &&
+             MaybeShowDeepScanFailureModalDialog(
+                 base::BindOnce(&DeepScanningRequest::Start,
+                                weak_ptr_factory_.GetWeakPtr()),
+                 base::BindOnce(&DeepScanningRequest::FinishRequest,
+                                weak_ptr_factory_.GetWeakPtr(),
+                                DownloadCheckResult::UNKNOWN),
+                 base::BindOnce(&DeepScanningRequest::OpenDownload,
+                                weak_ptr_factory_.GetWeakPtr()))) {
+    return;
   }
 
   FinishRequest(download_result);
@@ -225,4 +241,30 @@
   download_service_->RequestFinished(this);
 }
 
+bool DeepScanningRequest::MaybeShowDeepScanFailureModalDialog(
+    base::OnceClosure accept_callback,
+    base::OnceClosure cancel_callback,
+    base::OnceClosure open_now_callback) {
+  Profile* profile = Profile::FromBrowserContext(
+      content::DownloadItemUtils::GetBrowserContext(item_));
+  if (!profile)
+    return false;
+
+  Browser* browser =
+      chrome::FindTabbedBrowser(profile, /*match_original_profiles=*/false);
+  if (!browser)
+    return false;
+
+  DeepScanningFailureModalDialog::ShowForWebContents(
+      browser->tab_strip_model()->GetActiveWebContents(),
+      std::move(accept_callback), std::move(cancel_callback),
+      std::move(open_now_callback));
+  return true;
+}
+
+void DeepScanningRequest::OpenDownload() {
+  item_->OpenDownload();
+  FinishRequest(DownloadCheckResult::UNKNOWN);
+}
+
 }  // namespace safe_browsing
diff --git a/chrome/browser/safe_browsing/download_protection/deep_scanning_request.h b/chrome/browser/safe_browsing/download_protection/deep_scanning_request.h
index ced372c2..9fb5ac00 100644
--- a/chrome/browser/safe_browsing/download_protection/deep_scanning_request.h
+++ b/chrome/browser/safe_browsing/download_protection/deep_scanning_request.h
@@ -60,6 +60,15 @@
   // Callback when |item_| is destroyed.
   void OnDownloadDestroyed(download::DownloadItem* download) override;
 
+  // Called to attempt to show the modal dialog for scan failure. Returns
+  // whether the dialog was successfully shown.
+  bool MaybeShowDeepScanFailureModalDialog(base::OnceClosure accept_callback,
+                                           base::OnceClosure cancel_callback,
+                                           base::OnceClosure open_now_callback);
+
+  // Called to open the download. This is triggered by the timeout modal dialog.
+  void OpenDownload();
+
   // The download item to scan. This is unowned, and could become nullptr if the
   // download is destroyed.
   download::DownloadItem* item_;
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_util.h b/chrome/browser/safe_browsing/download_protection/download_protection_util.h
index de4be79d..1bc4eb8 100644
--- a/chrome/browser/safe_browsing/download_protection/download_protection_util.h
+++ b/chrome/browser/safe_browsing/download_protection/download_protection_util.h
@@ -27,7 +27,8 @@
   BLOCKED_TOO_LARGE,
   SENSITIVE_CONTENT_WARNING,
   SENSITIVE_CONTENT_BLOCK,
-  DEEP_SCANNED_SAFE
+  DEEP_SCANNED_SAFE,
+  PROMPT_FOR_SCANNING,
 };
 
 // Enum to keep track why a particular download verdict was chosen.
@@ -67,6 +68,7 @@
   REASON_SENSITIVE_CONTENT_WARNING = 31,
   REASON_SENSITIVE_CONTENT_BLOCK = 32,
   REASON_DEEP_SCANNED_SAFE = 33,
+  REASON_ADVANCED_PROTECTION_PROMPT = 34,
   REASON_MAX  // Always add new values before this one.
 };
 
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 68eaa55..1cb5563 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -93,6 +93,8 @@
     "chrome_select_file_policy.h",
     "color_chooser.h",
     "confirm_bubble.h",
+    "cookie_controls/cookie_controls_controller.cc",
+    "cookie_controls/cookie_controls_controller.h",
     "crypto_module_password_dialog.h",
     "cryptuiapi_shim.h",
     "enterprise_startup_dialog.h",
@@ -1451,6 +1453,7 @@
         "//chrome/browser/web_applications",
 
         # TODO(loyso): Erase these. crbug.com/877898.
+        "//chrome/browser/web_applications:common",
         "//chrome/browser/web_applications:web_applications_on_extensions",
         "//chrome/browser/web_applications/components",
         "//chrome/browser/web_applications/extensions",
@@ -2650,8 +2653,6 @@
       "autofill/payments/save_upi_bubble_controller_impl.cc",
       "autofill/payments/save_upi_bubble_controller_impl.h",
       "bubble_anchor_util.h",
-      "cookie_controls/cookie_controls_controller.cc",
-      "cookie_controls/cookie_controls_controller.h",
       "cookie_controls/cookie_controls_view.h",
       "manifest_web_app_browser_controller.cc",
       "manifest_web_app_browser_controller.h",
@@ -3178,10 +3179,14 @@
       "views/relaunch_notification/wall_clock_timer.h",
       "views/sad_tab_view.cc",
       "views/sad_tab_view.h",
+      "views/safe_browsing/deep_scanning_failure_modal_dialog.cc",
+      "views/safe_browsing/deep_scanning_failure_modal_dialog.h",
       "views/safe_browsing/deep_scanning_modal_dialog.cc",
       "views/safe_browsing/deep_scanning_modal_dialog.h",
       "views/safe_browsing/password_reuse_modal_warning_dialog.cc",
       "views/safe_browsing/password_reuse_modal_warning_dialog.h",
+      "views/safe_browsing/prompt_for_scanning_modal_dialog.cc",
+      "views/safe_browsing/prompt_for_scanning_modal_dialog.h",
       "views/send_tab_to_self/send_tab_to_self_bubble_device_button.cc",
       "views/send_tab_to_self/send_tab_to_self_bubble_device_button.h",
       "views/send_tab_to_self/send_tab_to_self_bubble_view_impl.cc",
@@ -4308,6 +4313,10 @@
 }
 
 if (is_android) {
+  java_cpp_enum("cookie_controls_controller_status_javagen") {
+    sources = [ "cookie_controls/cookie_controls_controller.h" ]
+  }
+
   java_cpp_enum("tab_model_enums_java") {
     sources = [ "android/tab_model/tab_model.h" ]
   }
diff --git a/chrome/browser/ui/app_list/app_service/app_service_app_icon_loader.cc b/chrome/browser/ui/app_list/app_service/app_service_app_icon_loader.cc
index bb22aeb..89488b5 100644
--- a/chrome/browser/ui/app_list/app_service/app_service_app_icon_loader.cc
+++ b/chrome/browser/ui/app_list/app_service/app_service_app_icon_loader.cc
@@ -35,6 +35,14 @@
   // Chrome, which should be hidden.
   if (app_id == kArcIntentHelperAppId)
     return false;
+
+  apps::AppServiceProxy* proxy =
+      apps::AppServiceProxyFactory::GetForProfile(profile());
+  if (!proxy || proxy->AppRegistryCache().GetAppType(app_id) ==
+                    apps::mojom::AppType::kUnknown) {
+    return false;
+  }
+
   return true;
 }
 
diff --git a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
index 3490eb3ec..cfcf921 100644
--- a/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
+++ b/chrome/browser/ui/ash/launcher/chrome_launcher_controller.cc
@@ -1303,6 +1303,17 @@
         std::make_unique<AppServiceAppIconLoader>(
             profile_, extension_misc::EXTENSION_ICON_MEDIUM, this);
     app_icon_loaders_.push_back(std::move(app_service_app_icon_loader));
+
+    // Some special extensions open new windows, and on Chrome OS, those windows
+    // should show the extension icon in the shelf. Extensions are not present
+    // in the App Service, so try loading extensions icon using
+    // ChromeAppIconLoader.
+    std::unique_ptr<extensions::ChromeAppIconLoader> chrome_app_icon_loader =
+        std::make_unique<extensions::ChromeAppIconLoader>(
+            profile_, extension_misc::EXTENSION_ICON_MEDIUM,
+            base::BindRepeating(&app_list::MaybeResizeAndPadIconForMd), this);
+    chrome_app_icon_loader->SetExtensionsOnly();
+    app_icon_loaders_.push_back(std::move(chrome_app_icon_loader));
   } else {
     // TODO(skuhne): The AppIconLoaderImpl has the same problem. Each loaded
     // image is associated with a profile (its loader requires the profile).
@@ -1352,9 +1363,19 @@
     std::unique_ptr<LauncherAppUpdater> app_service_app_updater(
         new LauncherAppServiceAppUpdater(this, profile()));
     app_updaters_.push_back(std::move(app_service_app_updater));
+
+    // Some special extensions open new windows, and on Chrome OS, those windows
+    // should show the extension icon in the shelf. Extensions are not present
+    // in the App Service, so use LauncherExtensionAppUpdater to handle
+    // extensions life-cycle events.
+    std::unique_ptr<LauncherExtensionAppUpdater> extension_app_updater(
+        new LauncherExtensionAppUpdater(this, profile(),
+                                        true /* extensions_only */));
+    app_updaters_.push_back(std::move(extension_app_updater));
   } else {
     std::unique_ptr<LauncherAppUpdater> extension_app_updater(
-        new LauncherExtensionAppUpdater(this, profile()));
+        new LauncherExtensionAppUpdater(this, profile(),
+                                        false /* extensions_only */));
     app_updaters_.push_back(std::move(extension_app_updater));
 
     if (arc::IsArcAllowedForProfile(profile())) {
diff --git a/chrome/browser/ui/ash/launcher/launcher_extension_app_updater.cc b/chrome/browser/ui/ash/launcher/launcher_extension_app_updater.cc
index 4817b53..8968599 100644
--- a/chrome/browser/ui/ash/launcher/launcher_extension_app_updater.cc
+++ b/chrome/browser/ui/ash/launcher/launcher_extension_app_updater.cc
@@ -13,10 +13,15 @@
 
 LauncherExtensionAppUpdater::LauncherExtensionAppUpdater(
     Delegate* delegate,
-    content::BrowserContext* browser_context)
-    : LauncherAppUpdater(delegate, browser_context) {
+    content::BrowserContext* browser_context,
+    bool extensions_only)
+    : LauncherAppUpdater(delegate, browser_context),
+      extensions_only_(extensions_only) {
   StartObservingExtensionRegistry();
 
+  if (extensions_only)
+    return;
+
   ArcAppListPrefs* prefs = ArcAppListPrefs::Get(browser_context);
   if (prefs)
     prefs->AddObserver(this);
@@ -25,6 +30,9 @@
 LauncherExtensionAppUpdater::~LauncherExtensionAppUpdater() {
   StopObservingExtensionRegistry();
 
+  if (extensions_only_)
+    return;
+
   ArcAppListPrefs* prefs = ArcAppListPrefs::Get(browser_context());
   if (prefs)
     prefs->RemoveObserver(this);
@@ -33,13 +41,17 @@
 void LauncherExtensionAppUpdater::OnExtensionLoaded(
     content::BrowserContext* browser_context,
     const extensions::Extension* extension) {
-  delegate()->OnAppInstalled(browser_context, extension->id());
+  if (ShouldHandleExtension(extension))
+    delegate()->OnAppInstalled(browser_context, extension->id());
 }
 
 void LauncherExtensionAppUpdater::OnExtensionUnloaded(
     content::BrowserContext* browser_context,
     const extensions::Extension* extension,
     extensions::UnloadedExtensionReason reason) {
+  if (!ShouldHandleExtension(extension))
+    return;
+
   if (reason == extensions::UnloadedExtensionReason::UNINSTALL)
     delegate()->OnAppUninstalledPrepared(browser_context, extension->id());
   else
@@ -50,7 +62,8 @@
     content::BrowserContext* browser_context,
     const extensions::Extension* extension,
     extensions::UninstallReason reason) {
-  delegate()->OnAppUninstalled(browser_context, extension->id());
+  if (ShouldHandleExtension(extension))
+    delegate()->OnAppUninstalled(browser_context, extension->id());
 }
 
 void LauncherExtensionAppUpdater::OnShutdown(
@@ -102,3 +115,8 @@
   for (const auto& iter : extension_ids)
     UpdateApp(iter);
 }
+
+bool LauncherExtensionAppUpdater::ShouldHandleExtension(
+    const extensions::Extension* extension) const {
+  return !extensions_only_ || extension->is_extension();
+}
diff --git a/chrome/browser/ui/ash/launcher/launcher_extension_app_updater.h b/chrome/browser/ui/ash/launcher/launcher_extension_app_updater.h
index dd3116d1..e0b272c 100644
--- a/chrome/browser/ui/ash/launcher/launcher_extension_app_updater.h
+++ b/chrome/browser/ui/ash/launcher/launcher_extension_app_updater.h
@@ -18,7 +18,8 @@
       public ArcAppListPrefs::Observer {
  public:
   LauncherExtensionAppUpdater(Delegate* delegate,
-                              content::BrowserContext* browser_context);
+                              content::BrowserContext* browser_context,
+                              bool extensions_only);
   ~LauncherExtensionAppUpdater() override;
 
   // ExtensionRegistryObserver:
@@ -46,8 +47,14 @@
   void UpdateApp(const std::string& app_id);
   void UpdateEquivalentApp(const std::string& arc_package_name);
 
+  bool ShouldHandleExtension(const extensions::Extension* extension) const;
+
   extensions::ExtensionRegistry* extension_registry_ = nullptr;
 
+  // Handles life-cycle events for extensions only if true, otherwise handles
+  // life-cycle events for both Chrome apps and extensions.
+  const bool extensions_only_;
+
   DISALLOW_COPY_AND_ASSIGN(LauncherExtensionAppUpdater);
 };
 
diff --git a/chrome/browser/ui/cookie_controls/cookie_controls_controller.h b/chrome/browser/ui/cookie_controls/cookie_controls_controller.h
index 2481c483..74358b2 100644
--- a/chrome/browser/ui/cookie_controls/cookie_controls_controller.h
+++ b/chrome/browser/ui/cookie_controls/cookie_controls_controller.h
@@ -22,15 +22,18 @@
 class CookieControlsView;
 
 // A controller for CookieControlsIconView and CookieControlsBubbleView.
+// GENERATED_JAVA_ENUM_PACKAGE: org.chromium.chrome.browser.settings.website
+// GENERATED_JAVA_CLASS_NAME_OVERRIDE: CookieControlsControllerStatus
 class CookieControlsController {
  public:
   enum class Status {
     kUninitialized,
-    // Cookie blocking is enabled.
+    // Third-Party cookie blocking is enabled.
     kEnabled,
-    // Cookie blocking is disabled.
+    // Third-Party cookie blocking is disabled.
     kDisabled,
-    // Cookie blocking is enabled in general but was disabled for this site.
+    // Third-Party cookie blocking is enabled in general but was disabled
+    // for this site.
     kDisabledForSite,
   };
 
diff --git a/chrome/browser/ui/extensions/application_launch.cc b/chrome/browser/ui/extensions/application_launch.cc
index cc04468..29e29a8 100644
--- a/chrome/browser/ui/extensions/application_launch.cc
+++ b/chrome/browser/ui/extensions/application_launch.cc
@@ -35,7 +35,7 @@
 #include "chrome/browser/web_applications/components/file_handler_manager.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/components/web_app_provider_base.h"
-#include "chrome/browser/web_applications/components/web_app_tab_helper.h"
+#include "chrome/browser/web_applications/components/web_app_tab_helper_base.h"
 #include "chrome/browser/web_applications/system_web_app_manager.h"
 #include "chrome/browser/web_launch/web_launch_files_helper.h"
 #include "chrome/common/chrome_features.h"
@@ -268,8 +268,8 @@
   }
 
   if (extension->from_bookmark()) {
-    web_app::WebAppTabHelper* tab_helper =
-        web_app::WebAppTabHelper::FromWebContents(contents);
+    web_app::WebAppTabHelperBase* tab_helper =
+        web_app::WebAppTabHelperBase::FromWebContents(contents);
     DCHECK(tab_helper);
     tab_helper->SetAppId(extension->id());
   }
@@ -445,8 +445,8 @@
   // TODO(https://crbug.com/1032443):
   // Eventually move this to browser_navigator.cc: CreateTargetContents().
   if (extension && extension->from_bookmark()) {
-    web_app::WebAppTabHelper* tab_helper =
-        web_app::WebAppTabHelper::FromWebContents(web_contents);
+    web_app::WebAppTabHelperBase* tab_helper =
+        web_app::WebAppTabHelperBase::FromWebContents(web_contents);
     DCHECK(tab_helper);
     tab_helper->SetAppId(extension->id());
   }
diff --git a/chrome/browser/ui/tab_helpers.cc b/chrome/browser/ui/tab_helpers.cc
index b5eeee713f..654b5f9c 100644
--- a/chrome/browser/ui/tab_helpers.cc
+++ b/chrome/browser/ui/tab_helpers.cc
@@ -139,8 +139,8 @@
 #include "chrome/browser/extensions/api/web_navigation/web_navigation_api.h"
 #include "chrome/browser/extensions/chrome_extension_web_contents_observer.h"
 #include "chrome/browser/extensions/tab_helper.h"
-#include "chrome/browser/web_applications/components/web_app_tab_helper.h"
 #include "chrome/browser/web_applications/components/web_app_utils.h"
+#include "chrome/browser/web_applications/web_app_tab_helper.h"
 #include "extensions/browser/view_type_utils.h"
 #endif
 
diff --git a/chrome/browser/ui/views/download/download_item_view.cc b/chrome/browser/ui/views/download/download_item_view.cc
index e104656..83d2d6a 100644
--- a/chrome/browser/ui/views/download/download_item_view.cc
+++ b/chrome/browser/ui/views/download/download_item_view.cc
@@ -45,6 +45,7 @@
 #include "chrome/browser/ui/views/download/download_shelf_view.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
 #include "chrome/browser/ui/views/safe_browsing/deep_scanning_modal_dialog.h"
+#include "chrome/browser/ui/views/safe_browsing/prompt_for_scanning_modal_dialog.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/download/public/common/download_danger_type.h"
@@ -664,18 +665,6 @@
     return;
   }
 
-  if (IsShowingDeepScanning() && sender == open_button_) {
-    content::WebContents* current_web_contents =
-        shelf_->browser()->tab_strip_model()->GetActiveWebContents();
-    open_now_modal_dialog_ = TabModalConfirmDialog::Create(
-        std::make_unique<safe_browsing::DeepScanningModalDialog>(
-            current_web_contents,
-            base::BindOnce(&DownloadItemView::OpenDownloadDuringAsyncScanning,
-                           weak_ptr_factory_.GetWeakPtr())),
-        current_web_contents);
-    return;
-  }
-
   if (sender == dropdown_button_) {
     // TODO(estade): this is copied from ToolbarActionView but should be shared
     // one way or another.
@@ -706,6 +695,29 @@
   }
 
   if (sender == open_button_) {
+    if (IsShowingDeepScanning()) {
+      content::WebContents* current_web_contents =
+          shelf_->browser()->tab_strip_model()->GetActiveWebContents();
+      open_now_modal_dialog_ = TabModalConfirmDialog::Create(
+          std::make_unique<safe_browsing::DeepScanningModalDialog>(
+              current_web_contents,
+              base::BindOnce(&DownloadItemView::OpenDownloadDuringAsyncScanning,
+                             weak_ptr_factory_.GetWeakPtr())),
+          current_web_contents);
+      return;
+    }
+    if (model_->GetDangerType() ==
+        download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING) {
+      content::WebContents* current_web_contents =
+          shelf_->browser()->tab_strip_model()->GetActiveWebContents();
+      safe_browsing::PromptForScanningModalDialog::ShowForWebContents(
+          current_web_contents,
+          base::BindOnce(&DownloadItemView::ConfirmDeepScanning,
+                         weak_ptr_factory_.GetWeakPtr()),
+          base::BindOnce(&DownloadItemView::BypassDeepScanning,
+                         weak_ptr_factory_.GetWeakPtr()));
+      return;
+    }
     if (IsShowingWarningDialog())
       return;
     if (complete_animation_.get() && complete_animation_->is_animating())
@@ -715,7 +727,7 @@
   }
 
   if (sender == scan_button_) {
-    DownloadCommands(model_.get()).ExecuteCommand(DownloadCommands::DEEP_SCAN);
+    ConfirmDeepScanning();
     return;
   }
 
@@ -1062,10 +1074,14 @@
       dangerous_label, /*listener=*/nullptr);
   dangerous_download_label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
   dangerous_download_label->SetAutoColorReadabilityEnabled(false);
+  dangerous_download_label->set_can_process_events_within_subtree(false);
   dangerous_download_label_ = AddChildView(std::move(dangerous_download_label));
   SizeLabelToMinWidth();
 
-  open_button_->SetEnabled(false);
+  bool open_button_enabled =
+      (model_->GetDangerType() ==
+       download::DOWNLOAD_DANGER_TYPE_PROMPT_FOR_SCANNING);
+  open_button_->SetEnabled(open_button_enabled);
   file_name_label_->SetVisible(false);
   status_label_->SetVisible(false);
   dropdown_button_->SetVisible(mode_ == MALICIOUS_MODE);
@@ -1506,3 +1522,12 @@
              ? 20
              : 27;
 }
+
+void DownloadItemView::ConfirmDeepScanning() {
+  DownloadCommands(model_.get()).ExecuteCommand(DownloadCommands::DEEP_SCAN);
+}
+
+void DownloadItemView::BypassDeepScanning() {
+  DownloadCommands(model_.get())
+      .ExecuteCommand(DownloadCommands::BYPASS_DEEP_SCANNING);
+}
diff --git a/chrome/browser/ui/views/download/download_item_view.h b/chrome/browser/ui/views/download/download_item_view.h
index 7e3cd4e..051cbc583 100644
--- a/chrome/browser/ui/views/download/download_item_view.h
+++ b/chrome/browser/ui/views/download/download_item_view.h
@@ -306,6 +306,12 @@
   // Returns the height/width of the error icon, in dp.
   static int GetErrorIconSize();
 
+  // Starts deep scanning for this download item.
+  void ConfirmDeepScanning();
+
+  // Bypasses the prompt for deep scanning for this download item.
+  void BypassDeepScanning();
+
   // The download shelf that owns us.
   DownloadShelfView* shelf_;
 
diff --git a/chrome/browser/ui/views/extensions/extensions_menu_view.cc b/chrome/browser/ui/views/extensions/extensions_menu_view.cc
index 161260e..4b7b125 100644
--- a/chrome/browser/ui/views/extensions/extensions_menu_view.cc
+++ b/chrome/browser/ui/views/extensions/extensions_menu_view.cc
@@ -206,11 +206,8 @@
             views::style::STYLE_SECONDARY);
         description->SetMultiLine(true);
         description->SetHorizontalAlignment(gfx::ALIGN_LEFT);
-        description->SetBorder(views::CreateEmptyBorder(
-            0, horizontal_spacing,
-            ChromeLayoutProvider::Get()->GetDistanceMetric(
-                DISTANCE_RELATED_CONTROL_VERTICAL_SMALL),
-            horizontal_spacing));
+        description->SetBorder(views::CreateEmptyBorder(0, horizontal_spacing,
+                                                        0, horizontal_spacing));
         container->AddChildView(std::move(description));
 
         // Add a (currently empty) section for the menu items of the section.
diff --git a/chrome/browser/ui/views/page_action/pwa_install_view.cc b/chrome/browser/ui/views/page_action/pwa_install_view.cc
index bdb8d442..0eb59ac 100644
--- a/chrome/browser/ui/views/page_action/pwa_install_view.cc
+++ b/chrome/browser/ui/views/page_action/pwa_install_view.cc
@@ -12,7 +12,6 @@
 #include "chrome/browser/ui/views/extensions/pwa_confirmation_bubble_view.h"
 #include "chrome/browser/ui/web_applications/web_app_dialog_utils.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
-#include "chrome/browser/web_applications/components/web_app_tab_helper.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/omnibox/browser/vector_icons.h"
 #include "ui/base/l10n/l10n_util.h"
diff --git a/chrome/browser/ui/views/safe_browsing/deep_scanning_failure_modal_dialog.cc b/chrome/browser/ui/views/safe_browsing/deep_scanning_failure_modal_dialog.cc
new file mode 100644
index 0000000..792a6a71
--- /dev/null
+++ b/chrome/browser/ui/views/safe_browsing/deep_scanning_failure_modal_dialog.cc
@@ -0,0 +1,114 @@
+// 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/ui/views/safe_browsing/deep_scanning_failure_modal_dialog.h"
+
+#include <memory>
+
+#include "chrome/browser/ui/views/chrome_layout_provider.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/constrained_window/constrained_window_views.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/views/controls/button/md_text_button.h"
+#include "ui/views/layout/grid_layout.h"
+#include "ui/views/window/dialog_delegate.h"
+
+namespace safe_browsing {
+
+/*static*/
+void DeepScanningFailureModalDialog::ShowForWebContents(
+    content::WebContents* web_contents,
+    base::OnceClosure accept_callback,
+    base::OnceClosure cancel_callback,
+    base::OnceClosure open_now_callback) {
+  constrained_window::ShowWebModalDialogViews(
+      new DeepScanningFailureModalDialog(std::move(accept_callback),
+                                         std::move(cancel_callback),
+                                         std::move(open_now_callback)),
+      web_contents);
+}
+
+DeepScanningFailureModalDialog::DeepScanningFailureModalDialog(
+    base::OnceClosure accept_callback,
+    base::OnceClosure cancel_callback,
+    base::OnceClosure open_now_callback)
+    : accept_callback_(std::move(accept_callback)),
+      cancel_callback_(std::move(cancel_callback)),
+      open_now_callback_(std::move(open_now_callback)) {
+  DialogDelegate::set_button_label(
+      ui::DIALOG_BUTTON_OK,
+      l10n_util::GetStringUTF16(
+          IDS_DEEP_SCANNING_TIMED_OUT_DIALOG_ACCEPT_BUTTON));
+  DialogDelegate::set_button_label(
+      ui::DIALOG_BUTTON_CANCEL,
+      l10n_util::GetStringUTF16(
+          IDS_DEEP_SCANNING_TIMED_OUT_DIALOG_CANCEL_BUTTON));
+  auto open_now_button = views::MdTextButton::CreateSecondaryUiButton(
+      this,
+      l10n_util::GetStringUTF16(IDS_DEEP_SCANNING_INFO_DIALOG_OPEN_NOW_BUTTON));
+  open_now_button_ = DialogDelegate::SetExtraView(std::move(open_now_button));
+
+  set_margins(ChromeLayoutProvider::Get()->GetDialogInsetsForContentType(
+      views::TEXT, views::TEXT));
+  views::GridLayout* layout =
+      SetLayoutManager(std::make_unique<views::GridLayout>());
+
+  // Use a fixed maximum message width, so longer messages will wrap.
+  const int kMaxMessageWidth = 400;
+  views::ColumnSet* cs = layout->AddColumnSet(0);
+  cs->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER,
+                views::GridLayout::kFixedSize, views::GridLayout::FIXED,
+                kMaxMessageWidth, false);
+
+  // Add the message label.
+  auto label = std::make_unique<views::Label>(
+      l10n_util::GetStringUTF16(IDS_DEEP_SCANNING_TIMED_OUT_DIALOG_MESSAGE),
+      views::style::CONTEXT_MESSAGE_BOX_BODY_TEXT,
+      views::style::STYLE_SECONDARY);
+  label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  label->SetMultiLine(true);
+  label->SizeToFit(kMaxMessageWidth);
+  layout->StartRow(views::GridLayout::kFixedSize, 0);
+  layout->AddView(std::move(label));
+}
+
+DeepScanningFailureModalDialog::~DeepScanningFailureModalDialog() = default;
+
+bool DeepScanningFailureModalDialog::IsDialogButtonEnabled(
+    ui::DialogButton button) const {
+  return (button == ui::DIALOG_BUTTON_OK || button == ui::DIALOG_BUTTON_CANCEL);
+}
+
+bool DeepScanningFailureModalDialog::Accept() {
+  std::move(accept_callback_).Run();
+  return true;
+}
+
+bool DeepScanningFailureModalDialog::Cancel() {
+  std::move(cancel_callback_).Run();
+  return true;
+}
+
+bool DeepScanningFailureModalDialog::ShouldShowCloseButton() const {
+  return false;
+}
+
+base::string16 DeepScanningFailureModalDialog::GetWindowTitle() const {
+  return l10n_util::GetStringUTF16(IDS_DEEP_SCANNING_TIMED_OUT_DIALOG_TITLE);
+}
+
+ui::ModalType DeepScanningFailureModalDialog::GetModalType() const {
+  return ui::MODAL_TYPE_CHILD;
+}
+
+void DeepScanningFailureModalDialog::ButtonPressed(views::Button* sender,
+                                                   const ui::Event& event) {
+  if (sender == open_now_button_) {
+    std::move(open_now_callback_).Run();
+    CancelDialog();
+  }
+}
+
+}  // namespace safe_browsing
diff --git a/chrome/browser/ui/views/safe_browsing/deep_scanning_failure_modal_dialog.h b/chrome/browser/ui/views/safe_browsing/deep_scanning_failure_modal_dialog.h
new file mode 100644
index 0000000..264daeb
--- /dev/null
+++ b/chrome/browser/ui/views/safe_browsing/deep_scanning_failure_modal_dialog.h
@@ -0,0 +1,69 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_SAFE_BROWSING_DEEP_SCANNING_FAILURE_MODAL_DIALOG_H_
+#define CHROME_BROWSER_UI_VIEWS_SAFE_BROWSING_DEEP_SCANNING_FAILURE_MODAL_DIALOG_H_
+
+#include "base/callback.h"
+#include "base/callback_forward.h"
+#include "base/timer/timer.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/window/dialog_delegate.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace safe_browsing {
+
+// A tab modal dialog that provides more information to the user about the
+// prompt for deep scanning.
+class DeepScanningFailureModalDialog : public views::DialogDelegateView,
+                                       public views::ButtonListener {
+ public:
+  // Show this dialog for the given |web_contents|.
+  static void ShowForWebContents(content::WebContents* web_contents,
+                                 base::OnceClosure accept_callback,
+                                 base::OnceClosure cancel_callback,
+                                 base::OnceClosure open_now_callback);
+
+  // Create a DeepScanningFailureModalDialog attached to |web_contents|. The
+  // dialog will call |accept_callback| if the user accepts the prompt.
+  DeepScanningFailureModalDialog(base::OnceClosure accept_callback,
+                                 base::OnceClosure cancel_callback,
+                                 base::OnceClosure open_now_callback);
+  DeepScanningFailureModalDialog(const DeepScanningFailureModalDialog&) =
+      delete;
+  DeepScanningFailureModalDialog& operator=(
+      const DeepScanningFailureModalDialog&) = delete;
+  ~DeepScanningFailureModalDialog() override;
+
+  // views::DialogDelegate implementation:
+  bool IsDialogButtonEnabled(ui::DialogButton button) const override;
+  bool Cancel() override;
+  bool Accept() override;
+  bool ShouldShowCloseButton() const override;
+
+  // views::WidgetDelegate implementation:
+  base::string16 GetWindowTitle() const override;
+  ui::ModalType GetModalType() const override;
+
+  // views::ButtonListener implementation:
+  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
+
+ private:
+  // The open now button for this dialog. The pointer is unowned, but this is a
+  // child View of this dialog's View, so it has the same lifetime.
+  views::Button* open_now_button_;
+
+  // The callbacks to trigger on each way the dialog is resolved.
+  base::OnceClosure accept_callback_;
+  base::OnceClosure cancel_callback_;
+  base::OnceClosure open_now_callback_;
+};
+
+}  // namespace safe_browsing
+
+#endif  // CHROME_BROWSER_UI_VIEWS_SAFE_BROWSING_DEEP_SCANNING_FAILURE_MODAL_DIALOG_H_
diff --git a/chrome/browser/ui/views/safe_browsing/prompt_for_scanning_modal_dialog.cc b/chrome/browser/ui/views/safe_browsing/prompt_for_scanning_modal_dialog.cc
new file mode 100644
index 0000000..35ff2329
--- /dev/null
+++ b/chrome/browser/ui/views/safe_browsing/prompt_for_scanning_modal_dialog.cc
@@ -0,0 +1,107 @@
+// 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/ui/views/safe_browsing/prompt_for_scanning_modal_dialog.h"
+
+#include <memory>
+
+#include "chrome/browser/ui/views/chrome_layout_provider.h"
+#include "chrome/grit/generated_resources.h"
+#include "components/constrained_window/constrained_window_views.h"
+#include "ui/base/l10n/l10n_util.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/views/controls/button/md_text_button.h"
+#include "ui/views/layout/grid_layout.h"
+#include "ui/views/window/dialog_delegate.h"
+
+namespace safe_browsing {
+
+/*static*/
+void PromptForScanningModalDialog::ShowForWebContents(
+    content::WebContents* web_contents,
+    base::OnceClosure accept_callback,
+    base::OnceClosure open_now_callback) {
+  constrained_window::ShowWebModalDialogViews(
+      new PromptForScanningModalDialog(std::move(accept_callback),
+                                       std::move(open_now_callback)),
+      web_contents);
+}
+
+PromptForScanningModalDialog::PromptForScanningModalDialog(
+    base::OnceClosure accept_callback,
+    base::OnceClosure open_now_callback)
+    : accept_callback_(std::move(accept_callback)),
+      open_now_callback_(std::move(open_now_callback)) {
+  DialogDelegate::set_button_label(
+      ui::DIALOG_BUTTON_OK,
+      l10n_util::GetStringUTF16(IDS_DEEP_SCANNING_INFO_DIALOG_ACCEPT_BUTTON));
+  DialogDelegate::set_button_label(
+      ui::DIALOG_BUTTON_CANCEL,
+      l10n_util::GetStringUTF16(IDS_DEEP_SCANNING_INFO_DIALOG_CANCEL_BUTTON));
+  auto open_now_button = views::MdTextButton::CreateSecondaryUiButton(
+      this,
+      l10n_util::GetStringUTF16(IDS_DEEP_SCANNING_INFO_DIALOG_OPEN_NOW_BUTTON));
+  open_now_button_ = DialogDelegate::SetExtraView(std::move(open_now_button));
+
+  set_margins(ChromeLayoutProvider::Get()->GetDialogInsetsForContentType(
+      views::TEXT, views::TEXT));
+  views::GridLayout* layout =
+      SetLayoutManager(std::make_unique<views::GridLayout>());
+
+  // Use a fixed maximum message width, so longer messages will wrap.
+  const int kMaxMessageWidth = 400;
+  views::ColumnSet* cs = layout->AddColumnSet(0);
+  cs->AddColumn(views::GridLayout::LEADING, views::GridLayout::CENTER,
+                views::GridLayout::kFixedSize, views::GridLayout::FIXED,
+                kMaxMessageWidth, false);
+
+  // Add the message label.
+  auto label = std::make_unique<views::Label>(
+      l10n_util::GetStringUTF16(IDS_DEEP_SCANNING_INFO_DIALOG_MESSAGE),
+      views::style::CONTEXT_MESSAGE_BOX_BODY_TEXT,
+      views::style::STYLE_SECONDARY);
+  label->SetHorizontalAlignment(gfx::ALIGN_LEFT);
+  label->SetMultiLine(true);
+  label->SizeToFit(kMaxMessageWidth);
+  layout->StartRow(views::GridLayout::kFixedSize, 0);
+  layout->AddView(std::move(label));
+}
+
+PromptForScanningModalDialog::~PromptForScanningModalDialog() = default;
+
+bool PromptForScanningModalDialog::IsDialogButtonEnabled(
+    ui::DialogButton button) const {
+  return (button == ui::DIALOG_BUTTON_OK || button == ui::DIALOG_BUTTON_CANCEL);
+}
+
+bool PromptForScanningModalDialog::Accept() {
+  std::move(accept_callback_).Run();
+  return true;
+}
+
+bool PromptForScanningModalDialog::Cancel() {
+  return true;
+}
+
+bool PromptForScanningModalDialog::ShouldShowCloseButton() const {
+  return false;
+}
+
+base::string16 PromptForScanningModalDialog::GetWindowTitle() const {
+  return l10n_util::GetStringUTF16(IDS_DEEP_SCANNING_INFO_DIALOG_TITLE);
+}
+
+ui::ModalType PromptForScanningModalDialog::GetModalType() const {
+  return ui::MODAL_TYPE_CHILD;
+}
+
+void PromptForScanningModalDialog::ButtonPressed(views::Button* sender,
+                                                 const ui::Event& event) {
+  if (sender == open_now_button_) {
+    std::move(open_now_callback_).Run();
+    CancelDialog();
+  }
+}
+
+}  // namespace safe_browsing
diff --git a/chrome/browser/ui/views/safe_browsing/prompt_for_scanning_modal_dialog.h b/chrome/browser/ui/views/safe_browsing/prompt_for_scanning_modal_dialog.h
new file mode 100644
index 0000000..5f0c1126
--- /dev/null
+++ b/chrome/browser/ui/views/safe_browsing/prompt_for_scanning_modal_dialog.h
@@ -0,0 +1,65 @@
+// 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_UI_VIEWS_SAFE_BROWSING_PROMPT_FOR_SCANNING_MODAL_DIALOG_H_
+#define CHROME_BROWSER_UI_VIEWS_SAFE_BROWSING_PROMPT_FOR_SCANNING_MODAL_DIALOG_H_
+
+#include "base/callback.h"
+#include "base/callback_forward.h"
+#include "base/timer/timer.h"
+#include "ui/base/ui_base_types.h"
+#include "ui/views/controls/button/button.h"
+#include "ui/views/window/dialog_delegate.h"
+
+namespace content {
+class WebContents;
+}
+
+namespace safe_browsing {
+
+// A tab modal dialog that provides more information to the user about the
+// prompt for deep scanning.
+class PromptForScanningModalDialog : public views::DialogDelegateView,
+                                     public views::ButtonListener {
+ public:
+  // Show this dialog for the given |web_contents|.
+  static void ShowForWebContents(content::WebContents* web_contents,
+                                 base::OnceClosure accept_callback,
+                                 base::OnceClosure open_now_callback);
+
+  // Create a PromptForScanningModalDialog attached to |web_contents|. The
+  // dialog will call |accept_callback| if the user accepts the prompt.
+  PromptForScanningModalDialog(base::OnceClosure accept_callback,
+                               base::OnceClosure open_now_callback);
+  PromptForScanningModalDialog(const PromptForScanningModalDialog&) = delete;
+  PromptForScanningModalDialog& operator=(const PromptForScanningModalDialog&) =
+      delete;
+  ~PromptForScanningModalDialog() override;
+
+  // views::DialogDelegate implementation:
+  bool IsDialogButtonEnabled(ui::DialogButton button) const override;
+  bool Cancel() override;
+  bool Accept() override;
+  bool ShouldShowCloseButton() const override;
+
+  // views::WidgetDelegate implementation:
+  base::string16 GetWindowTitle() const override;
+  ui::ModalType GetModalType() const override;
+
+  // views::ButtonListener implementation:
+  void ButtonPressed(views::Button* sender, const ui::Event& event) override;
+
+ private:
+  // The open now button for this dialog. The pointer is unowned, but this is a
+  // child View of this dialog's View, so it has the same lifetime.
+  views::Button* open_now_button_;
+
+  // The callbacks to trigger on each way the dialog is resolved.
+  base::OnceClosure accept_callback_;
+  base::OnceClosure open_now_callback_;
+};
+
+}  // namespace safe_browsing
+
+#endif  // CHROME_BROWSER_UI_VIEWS_SAFE_BROWSING_PROMPT_FOR_SCANNING_MODAL_DIALOG_H_
diff --git a/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc b/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc
index 4909436f..bc5dac97 100644
--- a/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc
+++ b/chrome/browser/ui/web_applications/test/web_app_browsertest_util.cc
@@ -16,7 +16,7 @@
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/components/web_app_provider_base.h"
-#include "chrome/browser/web_applications/components/web_app_tab_helper.h"
+#include "chrome/browser/web_applications/components/web_app_tab_helper_base.h"
 #include "chrome/common/web_application_info.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -65,9 +65,10 @@
           apps::mojom::AppLaunchSource::kSourceTest));
   DCHECK(web_contents);
 
-  WebAppTabHelper* tab_helper = WebAppTabHelper::FromWebContents(web_contents);
+  WebAppTabHelperBase* tab_helper =
+      WebAppTabHelperBase::FromWebContents(web_contents);
   DCHECK(tab_helper);
-  EXPECT_EQ(app_id, tab_helper->app_id());
+  EXPECT_EQ(app_id, tab_helper->GetAppId());
 
   Browser* browser = chrome::FindBrowserWithWebContents(web_contents);
   EXPECT_EQ(browser, chrome::FindLastActive());
diff --git a/chrome/browser/ui/web_applications/web_app_launch_manager.cc b/chrome/browser/ui/web_applications/web_app_launch_manager.cc
index 5800bb5..6d66d8d2 100644
--- a/chrome/browser/ui/web_applications/web_app_launch_manager.cc
+++ b/chrome/browser/ui/web_applications/web_app_launch_manager.cc
@@ -16,11 +16,11 @@
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
 #include "chrome/browser/web_applications/components/web_app_install_utils.h"
-#include "chrome/browser/web_applications/components/web_app_tab_helper.h"
 #include "chrome/browser/web_applications/system_web_app_manager.h"
 #include "chrome/browser/web_applications/web_app.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "chrome/browser/web_applications/web_app_registrar.h"
+#include "chrome/browser/web_applications/web_app_tab_helper.h"
 #include "chrome/browser/web_launch/web_launch_files_helper.h"
 #include "content/public/browser/render_view_host.h"
 #include "extensions/common/constants.h"
@@ -65,7 +65,8 @@
 
   // TODO(https://crbug.com/1032443):
   // Eventually move this to browser_navigator.cc: CreateTargetContents().
-  WebAppTabHelper* tab_helper = WebAppTabHelper::FromWebContents(web_contents);
+  WebAppTabHelperBase* tab_helper =
+      WebAppTabHelperBase::FromWebContents(web_contents);
   DCHECK(tab_helper);
   tab_helper->SetAppId(app_id);
 
diff --git a/chrome/browser/ui/web_applications/web_app_metrics.cc b/chrome/browser/ui/web_applications/web_app_metrics.cc
index 4708127..d730037c 100644
--- a/chrome/browser/ui/web_applications/web_app_metrics.cc
+++ b/chrome/browser/ui/web_applications/web_app_metrics.cc
@@ -11,7 +11,7 @@
 #include "chrome/browser/ui/browser_finder.h"
 #include "chrome/browser/ui/web_applications/web_app_metrics_factory.h"
 #include "chrome/browser/web_applications/components/app_registrar.h"
-#include "chrome/browser/web_applications/components/web_app_tab_helper.h"
+#include "chrome/browser/web_applications/components/web_app_tab_helper_base.h"
 #include "chrome/browser/web_applications/web_app_provider.h"
 #include "content/public/browser/web_contents.h"
 
@@ -97,9 +97,10 @@
                               engagement_type);
   }
 
-  // A presence of WebAppTabHelper with valid app_id indicates a web app.
-  WebAppTabHelper* tab_helper = WebAppTabHelper::FromWebContents(web_contents);
-  if (!tab_helper || tab_helper->app_id().empty())
+  // A presence of WebAppTabHelperBase with valid app_id indicates a web app.
+  WebAppTabHelperBase* tab_helper =
+      WebAppTabHelperBase::FromWebContents(web_contents);
+  if (!tab_helper || tab_helper->GetAppId().empty())
     return;
 
   // No HostedAppBrowserController if app is running as a tab in common browser.
diff --git a/chrome/browser/ui/webui/chromeos/crostini_installer/OWNERS b/chrome/browser/ui/webui/chromeos/crostini_installer/OWNERS
index 08850f4..3a2b81f 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_installer/OWNERS
+++ b/chrome/browser/ui/webui/chromeos/crostini_installer/OWNERS
@@ -1,2 +1,6 @@
+file://chrome/browser/chromeos/guest_os/OWNERS
+
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
+
+# COMPONENT: UI>Shell>Containers
diff --git a/chrome/browser/ui/webui/chromeos/crostini_upgrader/OWNERS b/chrome/browser/ui/webui/chromeos/crostini_upgrader/OWNERS
index 08850f4..3a2b81f 100644
--- a/chrome/browser/ui/webui/chromeos/crostini_upgrader/OWNERS
+++ b/chrome/browser/ui/webui/chromeos/crostini_upgrader/OWNERS
@@ -1,2 +1,6 @@
+file://chrome/browser/chromeos/guest_os/OWNERS
+
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
+
+# COMPONENT: UI>Shell>Containers
diff --git a/chrome/browser/ui/webui/downloads/OWNERS b/chrome/browser/ui/webui/downloads/OWNERS
index 23fd391..81029b1 100644
--- a/chrome/browser/ui/webui/downloads/OWNERS
+++ b/chrome/browser/ui/webui/downloads/OWNERS
@@ -1,7 +1,5 @@
 file://components/download/OWNERS
 
-dbeam@chromium.org
-
 per-file *.mojom=set noparent
 per-file *.mojom=file://ipc/SECURITY_OWNERS
 
diff --git a/chrome/browser/web_applications/BUILD.gn b/chrome/browser/web_applications/BUILD.gn
index 6f07a92..d6c3c149 100644
--- a/chrome/browser/web_applications/BUILD.gn
+++ b/chrome/browser/web_applications/BUILD.gn
@@ -9,6 +9,26 @@
 group("web_app_test_group") {
 }
 
+# Implementations that are common to both BMO/Extensions backends.
+# TODO(alancutter): Migrate sources from :web_applications into here where
+# possible.
+# TODO(https://crbug.com/877898): Merge this into :web_applications once all
+# Extension codepaths have been removed.
+source_set("common") {
+  sources = [
+    "web_app_tab_helper.cc",
+    "web_app_tab_helper.h",
+  ]
+
+  deps = [
+    ":web_app_group",
+    "//chrome/browser/web_applications/components",
+    "//chrome/common",
+    "//content/public/browser",
+    "//skia",
+  ]
+}
+
 source_set("web_applications") {
   sources = [
     "external_web_app_manager.cc",
@@ -51,6 +71,7 @@
   ]
 
   deps = [
+    ":common",
     ":web_app_group",
     "//chrome/browser/web_applications/components",
     "//chrome/common",
diff --git a/chrome/browser/web_applications/components/BUILD.gn b/chrome/browser/web_applications/components/BUILD.gn
index bf276534..a571dba 100644
--- a/chrome/browser/web_applications/components/BUILD.gn
+++ b/chrome/browser/web_applications/components/BUILD.gn
@@ -57,8 +57,8 @@
     "web_app_provider_base_factory.h",
     "web_app_shortcut.cc",
     "web_app_shortcut.h",
-    "web_app_tab_helper.cc",
-    "web_app_tab_helper.h",
+    "web_app_tab_helper_base.cc",
+    "web_app_tab_helper_base.h",
     "web_app_ui_manager.h",
     "web_app_url_loader.cc",
     "web_app_url_loader.h",
diff --git a/chrome/browser/web_applications/components/app_shortcut_manager.cc b/chrome/browser/web_applications/components/app_shortcut_manager.cc
index 71c8f53..442ada3 100644
--- a/chrome/browser/web_applications/components/app_shortcut_manager.cc
+++ b/chrome/browser/web_applications/components/app_shortcut_manager.cc
@@ -39,6 +39,16 @@
   observers_.RemoveObserver(observer);
 }
 
+void AppShortcutManager::OnWebAppWillBeUninstalled(const AppId& app_id) {
+  std::unique_ptr<ShortcutInfo> shortcut_info = BuildShortcutInfo(app_id);
+  base::FilePath shortcut_data_dir =
+      internals::GetShortcutDataDir(*shortcut_info);
+
+  internals::PostShortcutIOTask(
+      base::BindOnce(&internals::DeletePlatformShortcuts, shortcut_data_dir),
+      std::move(shortcut_info));
+}
+
 bool AppShortcutManager::CanCreateShortcuts() const {
 #if defined(OS_CHROMEOS)
   return false;
diff --git a/chrome/browser/web_applications/components/app_shortcut_manager.h b/chrome/browser/web_applications/components/app_shortcut_manager.h
index e4f041e..a8f42edc 100644
--- a/chrome/browser/web_applications/components/app_shortcut_manager.h
+++ b/chrome/browser/web_applications/components/app_shortcut_manager.h
@@ -44,6 +44,9 @@
   void AddObserver(AppShortcutObserver* observer);
   void RemoveObserver(AppShortcutObserver* observer);
 
+  // AppRegistrarObserver:
+  void OnWebAppWillBeUninstalled(const AppId& app_id) override;
+
   // Tells the AppShortcutManager that no shortcuts should actually be written
   // to the disk.
   void SuppressShortcutsForTesting();
@@ -55,6 +58,10 @@
                                bool add_to_desktop,
                                CreateShortcutsCallback callback);
 
+  // Builds initial ShortcutInfo without |ShortcutInfo::favicon| being read.
+  virtual std::unique_ptr<ShortcutInfo> BuildShortcutInfo(
+      const AppId& app_id) = 0;
+
   // The result of a call to GetShortcutInfo.
   using GetShortcutInfoCallback =
       base::OnceCallback<void(std::unique_ptr<ShortcutInfo>)>;
diff --git a/chrome/browser/web_applications/components/manifest_update_manager_browsertest.cc b/chrome/browser/web_applications/components/manifest_update_manager_browsertest.cc
index 68d291e..1ec4d7d 100644
--- a/chrome/browser/web_applications/components/manifest_update_manager_browsertest.cc
+++ b/chrome/browser/web_applications/components/manifest_update_manager_browsertest.cc
@@ -21,7 +21,6 @@
 #include "chrome/browser/web_applications/components/pending_app_manager.h"
 #include "chrome/browser/web_applications/components/web_app_constants.h"
 #include "chrome/browser/web_applications/components/web_app_provider_base.h"
-#include "chrome/browser/web_applications/components/web_app_tab_helper.h"
 #include "chrome/browser/web_applications/test/web_app_test.h"
 #include "chrome/common/chrome_features.h"
 #include "chrome/test/base/in_process_browser_test.h"
diff --git a/chrome/browser/web_applications/components/web_app_file_handler_registration_linux.cc b/chrome/browser/web_applications/components/web_app_file_handler_registration_linux.cc
index 7aef4c2..828b5de00 100644
--- a/chrome/browser/web_applications/components/web_app_file_handler_registration_linux.cc
+++ b/chrome/browser/web_applications/components/web_app_file_handler_registration_linux.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/app_shortcut_manager.h"
 #include "chrome/browser/web_applications/components/web_app_provider_base.h"
 #include "chrome/browser/web_applications/components/web_app_shortcut.h"
@@ -26,6 +27,16 @@
       base::DoNothing());
 }
 
+void UpdateFileHandlerRegistrationInOs(const AppId& app_id, Profile* profile) {
+  // On Linux, file associations are managed through shortcuts in the app menu,
+  // so after enabling or disabling file handling for an app its shortcuts
+  // need to be recreated.
+  AppShortcutManager& shortcut_manager =
+      WebAppProviderBase::GetProviderBase(profile)->shortcut_manager();
+  shortcut_manager.GetShortcutInfoForApp(
+      app_id, base::BindOnce(&OnShortcutInfoReceived));
+}
+
 }  // namespace
 
 bool ShouldRegisterFileHandlersWithOs() {
@@ -37,14 +48,18 @@
                                 Profile* profile,
                                 const std::set<std::string>& file_extensions,
                                 const std::set<std::string>& mime_types) {
-  AppShortcutManager& shortcut_manager =
-      WebAppProviderBase::GetProviderBase(profile)->shortcut_manager();
-  shortcut_manager.GetShortcutInfoForApp(
-      app_id, base::BindOnce(OnShortcutInfoReceived));
+  UpdateFileHandlerRegistrationInOs(app_id, profile);
 }
 
 void UnregisterFileHandlersWithOs(const AppId& app_id, Profile* profile) {
-  // TODO(harrisjay): Add support for unregistering file handlers.
+  // If this was triggered as part of the uninstallation process, nothing more
+  // is needed. Uninstalling already cleans up shortcuts (and thus, file
+  // handlers).
+  auto* provider = WebAppProviderBase::GetProviderBase(profile);
+  if (!provider->registrar().IsInstalled(app_id))
+    return;
+
+  UpdateFileHandlerRegistrationInOs(app_id, profile);
 }
 
 }  // namespace web_app
diff --git a/chrome/browser/web_applications/components/web_app_tab_helper_base.cc b/chrome/browser/web_applications/components/web_app_tab_helper_base.cc
new file mode 100644
index 0000000..c2ce7ca
--- /dev/null
+++ b/chrome/browser/web_applications/components/web_app_tab_helper_base.cc
@@ -0,0 +1,11 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/web_applications/components/web_app_tab_helper_base.h"
+
+namespace web_app {
+
+WEB_CONTENTS_USER_DATA_KEY_IMPL(WebAppTabHelperBase)
+
+}  // namespace web_app
diff --git a/chrome/browser/web_applications/components/web_app_tab_helper_base.h b/chrome/browser/web_applications/components/web_app_tab_helper_base.h
new file mode 100644
index 0000000..a222ffc
--- /dev/null
+++ b/chrome/browser/web_applications/components/web_app_tab_helper_base.h
@@ -0,0 +1,43 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_TAB_HELPER_BASE_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_TAB_HELPER_BASE_H_
+
+#include "chrome/browser/web_applications/components/web_app_helpers.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+namespace base {
+class UnguessableToken;
+}
+
+namespace web_app {
+
+// Public interface for WebAppTabHelper.
+class WebAppTabHelperBase
+    : public content::WebContentsUserData<WebAppTabHelperBase> {
+ public:
+  using content::WebContentsUserData<WebAppTabHelperBase>::FromWebContents;
+
+  virtual const AppId& GetAppId() const = 0;
+  virtual void SetAppId(const AppId& app_id) = 0;
+
+  // These methods require an app associated with the tab (valid GetAppId()).
+
+  // Returns true if the app was installed by user, false if default installed.
+  virtual bool IsUserInstalled() const = 0;
+  // For user-installed apps:
+  // Returns true if the app was installed through the install button.
+  // Returns false if the app was installed through the create shortcut button.
+  virtual bool IsFromInstallButton() const = 0;
+
+  virtual const base::UnguessableToken& GetAudioFocusGroupIdForTesting()
+      const = 0;
+
+  WEB_CONTENTS_USER_DATA_KEY_DECL();
+};
+
+}  // namespace web_app
+
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_TAB_HELPER_BASE_H_
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_shortcut_manager.cc b/chrome/browser/web_applications/extensions/bookmark_app_shortcut_manager.cc
index 8f56264..40fc0a8 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_shortcut_manager.cc
+++ b/chrome/browser/web_applications/extensions/bookmark_app_shortcut_manager.cc
@@ -7,6 +7,7 @@
 #include "base/callback.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/web_applications/components/web_app_shortcut.h"
+#include "chrome/browser/web_applications/extensions/bookmark_app_registrar.h"
 #include "chrome/browser/web_applications/extensions/web_app_extension_shortcut.h"
 #include "extensions/browser/extension_registry.h"
 
@@ -17,6 +18,17 @@
 
 BookmarkAppShortcutManager::~BookmarkAppShortcutManager() = default;
 
+std::unique_ptr<web_app::ShortcutInfo>
+BookmarkAppShortcutManager::BuildShortcutInfo(const web_app::AppId& app_id) {
+  BookmarkAppRegistrar* registry = registrar()->AsBookmarkAppRegistrar();
+  DCHECK(registry);
+
+  const Extension* app = registry->FindExtension(app_id);
+  DCHECK(app);
+
+  return web_app::ShortcutInfoForExtensionAndProfile(app, profile());
+}
+
 void BookmarkAppShortcutManager::GetShortcutInfoForApp(
     const web_app::AppId& app_id,
     GetShortcutInfoCallback callback) {
diff --git a/chrome/browser/web_applications/extensions/bookmark_app_shortcut_manager.h b/chrome/browser/web_applications/extensions/bookmark_app_shortcut_manager.h
index a9d8f729..61f0e80 100644
--- a/chrome/browser/web_applications/extensions/bookmark_app_shortcut_manager.h
+++ b/chrome/browser/web_applications/extensions/bookmark_app_shortcut_manager.h
@@ -17,6 +17,9 @@
   explicit BookmarkAppShortcutManager(Profile* profile);
   ~BookmarkAppShortcutManager() override;
 
+  // AppShortcutManager:
+  std::unique_ptr<web_app::ShortcutInfo> BuildShortcutInfo(
+      const web_app::AppId& app_id) override;
   void GetShortcutInfoForApp(const web_app::AppId& app_id,
                              GetShortcutInfoCallback callback) override;
 
diff --git a/chrome/browser/web_applications/extensions/web_app_audio_focus_browsertest.cc b/chrome/browser/web_applications/extensions/web_app_audio_focus_browsertest.cc
index e385695b..85a3f83 100644
--- a/chrome/browser/web_applications/extensions/web_app_audio_focus_browsertest.cc
+++ b/chrome/browser/web_applications/extensions/web_app_audio_focus_browsertest.cc
@@ -7,7 +7,7 @@
 #include "chrome/browser/extensions/browsertest_util.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/ui/browser.h"
-#include "chrome/browser/web_applications/components/web_app_tab_helper.h"
+#include "chrome/browser/web_applications/components/web_app_tab_helper_base.h"
 #include "chrome/common/web_application_info.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "content/public/browser/notification_service.h"
@@ -75,8 +75,9 @@
 
   const base::UnguessableToken& GetAudioFocusGroupId(
       content::WebContents* web_contents) {
-    WebAppTabHelper* helper = WebAppTabHelper::FromWebContents(web_contents);
-    return helper->audio_focus_group_id_;
+    WebAppTabHelperBase* helper =
+        WebAppTabHelperBase::FromWebContents(web_contents);
+    return helper->GetAudioFocusGroupIdForTesting();
   }
 
  private:
diff --git a/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc b/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc
index 7a09aaa..0a30ec7 100644
--- a/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc
+++ b/chrome/browser/web_applications/extensions/web_app_extension_shortcut.cc
@@ -20,6 +20,7 @@
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/browser/web_applications/components/file_handler_manager.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
+#include "chrome/browser/web_applications/components/web_app_provider_base.h"
 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
 #include "chrome/common/pref_names.h"
 #include "components/prefs/pref_service.h"
@@ -178,11 +179,18 @@
   shortcut_info->profile_name =
       profile->GetPrefs()->GetString(prefs::kProfileName);
   shortcut_info->version_for_display = app->GetVersionForDisplay();
-  if (const auto* info = extensions::FileHandlers::GetFileHandlers(app)) {
-    shortcut_info->file_handler_extensions =
-        web_app::GetFileExtensionsFromFileHandlers(*info);
-    shortcut_info->file_handler_mime_types =
-        web_app::GetMimeTypesFromFileHandlers(*info);
+
+  // File Handlers should only be included in bookmark apps.
+  if (app->from_bookmark()) {
+    FileHandlerManager& file_handler_manager =
+        WebAppProviderBase::GetProviderBase(profile)->file_handler_manager();
+    if (const auto* file_handlers =
+            file_handler_manager.GetEnabledFileHandlers(app->id())) {
+      shortcut_info->file_handler_extensions =
+          web_app::GetFileExtensionsFromFileHandlers(*file_handlers);
+      shortcut_info->file_handler_mime_types =
+          web_app::GetMimeTypesFromFileHandlers(*file_handlers);
+    }
   }
 
   return shortcut_info;
diff --git a/chrome/browser/web_applications/test/test_app_shortcut_manager.cc b/chrome/browser/web_applications/test/test_app_shortcut_manager.cc
index 02c2430..7b64e91 100644
--- a/chrome/browser/web_applications/test/test_app_shortcut_manager.cc
+++ b/chrome/browser/web_applications/test/test_app_shortcut_manager.cc
@@ -44,6 +44,12 @@
                                 std::move(callback), success));
 }
 
+std::unique_ptr<ShortcutInfo> TestAppShortcutManager::BuildShortcutInfo(
+    const AppId& app_id) {
+  NOTIMPLEMENTED();
+  return nullptr;
+}
+
 void TestAppShortcutManager::GetShortcutInfoForApp(
     const AppId& app_id,
     GetShortcutInfoCallback callback) {
diff --git a/chrome/browser/web_applications/test/test_app_shortcut_manager.h b/chrome/browser/web_applications/test/test_app_shortcut_manager.h
index b74c726..5168b65 100644
--- a/chrome/browser/web_applications/test/test_app_shortcut_manager.h
+++ b/chrome/browser/web_applications/test/test_app_shortcut_manager.h
@@ -40,6 +40,7 @@
   void CreateShortcuts(const AppId& app_id,
                        bool on_desktop,
                        CreateShortcutsCallback callback) override;
+  std::unique_ptr<ShortcutInfo> BuildShortcutInfo(const AppId& app_id) override;
   void GetShortcutInfoForApp(const AppId& app_id,
                              GetShortcutInfoCallback callback) override;
 
diff --git a/chrome/browser/web_applications/web_app_shortcut_manager.cc b/chrome/browser/web_applications/web_app_shortcut_manager.cc
index c56e83a..0eab5ab 100644
--- a/chrome/browser/web_applications/web_app_shortcut_manager.cc
+++ b/chrome/browser/web_applications/web_app_shortcut_manager.cc
@@ -36,17 +36,11 @@
 
 WebAppShortcutManager::~WebAppShortcutManager() = default;
 
-void WebAppShortcutManager::OnWebAppWillBeUninstalled(const AppId& app_id) {
+std::unique_ptr<ShortcutInfo> WebAppShortcutManager::BuildShortcutInfo(
+    const AppId& app_id) {
   const WebApp* app = GetWebAppRegistrar().GetAppById(app_id);
   DCHECK(app);
-
-  std::unique_ptr<ShortcutInfo> shortcut_info = BuildShortcutInfoForWebApp(app);
-  base::FilePath shortcut_data_dir =
-      internals::GetShortcutDataDir(*shortcut_info);
-
-  internals::PostShortcutIOTask(
-      base::BindOnce(&internals::DeletePlatformShortcuts, shortcut_data_dir),
-      std::move(shortcut_info));
+  return BuildShortcutInfoForWebApp(app);
 }
 
 void WebAppShortcutManager::GetShortcutInfoForApp(
diff --git a/chrome/browser/web_applications/web_app_shortcut_manager.h b/chrome/browser/web_applications/web_app_shortcut_manager.h
index bc9cd85b..dc0686e0 100644
--- a/chrome/browser/web_applications/web_app_shortcut_manager.h
+++ b/chrome/browser/web_applications/web_app_shortcut_manager.h
@@ -32,10 +32,8 @@
                         FileHandlerManager* file_handler_manager);
   ~WebAppShortcutManager() override;
 
-  // AppRegistrarObserver:
-  void OnWebAppWillBeUninstalled(const AppId& app_id) override;
-
   // AppShortcutManager:
+  std::unique_ptr<ShortcutInfo> BuildShortcutInfo(const AppId& app_id) override;
   void GetShortcutInfoForApp(const AppId& app_id,
                              GetShortcutInfoCallback callback) override;
 
diff --git a/chrome/browser/web_applications/components/web_app_tab_helper.cc b/chrome/browser/web_applications/web_app_tab_helper.cc
similarity index 87%
rename from chrome/browser/web_applications/components/web_app_tab_helper.cc
rename to chrome/browser/web_applications/web_app_tab_helper.cc
index f0497639..31da9345 100644
--- a/chrome/browser/web_applications/components/web_app_tab_helper.cc
+++ b/chrome/browser/web_applications/web_app_tab_helper.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/web_applications/components/web_app_tab_helper.h"
+#include "chrome/browser/web_applications/web_app_tab_helper.h"
 
 #include "base/unguessable_token.h"
 #include "chrome/browser/profiles/profile.h"
@@ -17,7 +17,13 @@
 
 namespace web_app {
 
-WEB_CONTENTS_USER_DATA_KEY_IMPL(WebAppTabHelper)
+void WebAppTabHelper::CreateForWebContents(content::WebContents* contents) {
+  DCHECK(contents);
+  if (!FromWebContents(contents)) {
+    contents->SetUserData(UserDataKey(),
+                          std::make_unique<WebAppTabHelper>(contents));
+  }
+}
 
 WebAppTabHelper::WebAppTabHelper(content::WebContents* web_contents)
     : content::WebContentsObserver(web_contents),
@@ -31,6 +37,26 @@
 
 WebAppTabHelper::~WebAppTabHelper() = default;
 
+const AppId& WebAppTabHelper::GetAppId() const {
+  return app_id_;
+}
+
+bool WebAppTabHelper::IsUserInstalled() const {
+  return !app_id_.empty() && provider_->registrar().WasInstalledByUser(app_id_);
+}
+
+bool WebAppTabHelper::IsFromInstallButton() const {
+  // TODO(loyso): Use something better to record apps installed from promoted
+  // UIs. crbug.com/774918.
+  return !app_id_.empty() &&
+         provider_->registrar().GetAppScope(app_id_).has_value();
+}
+
+const base::UnguessableToken& WebAppTabHelper::GetAudioFocusGroupIdForTesting()
+    const {
+  return audio_focus_group_id_;
+}
+
 void WebAppTabHelper::SetAppId(const AppId& app_id) {
   DCHECK(app_id.empty() || provider_->registrar().IsInstalled(app_id));
   if (app_id_ == app_id)
@@ -64,18 +90,7 @@
   auto* new_tab_helper = FromWebContents(new_web_contents);
 
   // Clone common state:
-  new_tab_helper->SetAppId(app_id());
-}
-
-bool WebAppTabHelper::IsUserInstalled() const {
-  return !app_id_.empty() && provider_->registrar().WasInstalledByUser(app_id_);
-}
-
-bool WebAppTabHelper::IsFromInstallButton() const {
-  // TODO(loyso): Use something better to record apps installed from promoted
-  // UIs. crbug.com/774918.
-  return !app_id_.empty() &&
-         provider_->registrar().GetAppScope(app_id_).has_value();
+  new_tab_helper->SetAppId(GetAppId());
 }
 
 bool WebAppTabHelper::IsInAppWindow() const {
@@ -90,7 +105,7 @@
 }
 
 void WebAppTabHelper::OnWebAppUninstalled(const AppId& uninstalled_app_id) {
-  if (app_id() == uninstalled_app_id)
+  if (GetAppId() == uninstalled_app_id)
     ResetAppId();
 }
 
diff --git a/chrome/browser/web_applications/components/web_app_tab_helper.h b/chrome/browser/web_applications/web_app_tab_helper.h
similarity index 69%
rename from chrome/browser/web_applications/components/web_app_tab_helper.h
rename to chrome/browser/web_applications/web_app_tab_helper.h
index ed53d7c..02be6cae 100644
--- a/chrome/browser/web_applications/components/web_app_tab_helper.h
+++ b/chrome/browser/web_applications/web_app_tab_helper.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_TAB_HELPER_H_
-#define CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_TAB_HELPER_H_
+#ifndef CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_TAB_HELPER_H_
+#define CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_TAB_HELPER_H_
 
 #include "base/macros.h"
 #include "base/scoped_observer.h"
@@ -11,8 +11,8 @@
 #include "chrome/browser/web_applications/components/app_registrar.h"
 #include "chrome/browser/web_applications/components/app_registrar_observer.h"
 #include "chrome/browser/web_applications/components/web_app_helpers.h"
+#include "chrome/browser/web_applications/components/web_app_tab_helper_base.h"
 #include "content/public/browser/web_contents_observer.h"
-#include "content/public/browser/web_contents_user_data.h"
 
 namespace content {
 class WebContents;
@@ -24,20 +24,21 @@
 
 // Per-tab web app helper. Allows to associate a tab (web page) with a web app
 // (or legacy bookmark app).
-class WebAppTabHelper : public content::WebContentsObserver,
-                        public content::WebContentsUserData<WebAppTabHelper>,
+class WebAppTabHelper : public WebAppTabHelperBase,
+                        public content::WebContentsObserver,
                         public AppRegistrarObserver {
  public:
-  using content::WebContentsUserData<WebAppTabHelper>::CreateForWebContents;
-  using content::WebContentsUserData<WebAppTabHelper>::FromWebContents;
+  static void CreateForWebContents(content::WebContents* contents);
 
   explicit WebAppTabHelper(content::WebContents* web_contents);
   ~WebAppTabHelper() override;
 
-  const AppId& app_id() const { return app_id_; }
-
-  // Set associated app_id.
-  void SetAppId(const AppId& app_id);
+  // WebAppTabHelperBase:
+  const AppId& GetAppId() const override;
+  void SetAppId(const AppId& app_id) override;
+  bool IsUserInstalled() const override;
+  bool IsFromInstallButton() const override;
+  const base::UnguessableToken& GetAudioFocusGroupIdForTesting() const override;
 
   // content::WebContentsObserver:
   void DidFinishNavigation(
@@ -46,18 +47,7 @@
       content::WebContents* old_web_contents,
       content::WebContents* new_web_contents) override;
 
-  // These methods require an app associated with the tab (valid app_id()).
-  //
-  // Returns true if the app was installed by user, false if default installed.
-  bool IsUserInstalled() const;
-  // For user-installed apps:
-  // Returns true if the app was installed through the install button.
-  // Returns false if the app was installed through the create shortcut button.
-  bool IsFromInstallButton() const;
-
  private:
-  WEB_CONTENTS_USER_DATA_KEY_DECL();
-
   friend class WebAppAudioFocusBrowserTest;
   friend class content::WebContentsUserData<WebAppTabHelper>;
 
@@ -98,4 +88,4 @@
 
 }  // namespace web_app
 
-#endif  // CHROME_BROWSER_WEB_APPLICATIONS_COMPONENTS_WEB_APP_TAB_HELPER_H_
+#endif  // CHROME_BROWSER_WEB_APPLICATIONS_WEB_APP_TAB_HELPER_H_
diff --git a/chrome/common/extensions/extension_constants.cc b/chrome/common/extensions/extension_constants.cc
index 72633ec..6f0d2be 100644
--- a/chrome/common/extensions/extension_constants.cc
+++ b/chrome/common/extensions/extension_constants.cc
@@ -2,9 +2,11 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include "chrome/common/extensions/extension_constants.h"
+
 #include "base/macros.h"
 #include "build/build_config.h"
-#include "chrome/common/extensions/extension_constants.h"
+#include "extensions/common/constants.h"
 
 namespace extension_urls {
 
@@ -77,6 +79,7 @@
     kAutoclickExtensionId,
     kSelectToSpeakExtensionId,
     kSwitchAccessExtensionId,
+    kFilesManagerAppId,
     kFirstRunDialogId,
     kEspeakSpeechSynthesisExtensionId,
     kGoogleSpeechSynthesisExtensionId,
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 37fe96b8..beb85488 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -1500,6 +1500,7 @@
         "../browser/policy/accessibility_policy_browsertest.cc",
         "../browser/policy/arc_policy_browsertest.cc",
         "../browser/policy/assistant_policy_browsertest.cc",
+        "../browser/renderer_context_menu/quick_answers_menu_observer_browsertest.cc",
       ]
     }
 
diff --git a/chrome/test/base/in_process_browser_test_browsertest.cc b/chrome/test/base/in_process_browser_test_browsertest.cc
index c8f712a..cb2ed68 100644
--- a/chrome/test/base/in_process_browser_test_browsertest.cc
+++ b/chrome/test/base/in_process_browser_test_browsertest.cc
@@ -21,6 +21,7 @@
 #include "content/public/common/content_switches.h"
 #include "net/base/filename_util.h"
 #include "net/base/net_errors.h"
+#include "net/dns/public/resolve_error_info.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
@@ -44,7 +45,8 @@
   explicit LoadFailObserver(content::WebContents* contents)
       : content::WebContentsObserver(contents),
         failed_load_(false),
-        error_code_(net::OK) { }
+        error_code_(net::OK),
+        resolve_error_info_(net::ResolveErrorInfo(net::OK)) {}
 
   void DidFinishNavigation(
       content::NavigationHandle* navigation_handle) override {
@@ -53,16 +55,21 @@
 
     failed_load_ = true;
     error_code_ = navigation_handle->GetNetErrorCode();
+    resolve_error_info_ = navigation_handle->GetResolveErrorInfo();
     validated_url_ = navigation_handle->GetURL();
   }
 
   bool failed_load() const { return failed_load_; }
   net::Error error_code() const { return error_code_; }
+  net::ResolveErrorInfo resolve_error_info() const {
+    return resolve_error_info_;
+  }
   const GURL& validated_url() const { return validated_url_; }
 
  private:
   bool failed_load_;
   net::Error error_code_;
+  net::ResolveErrorInfo resolve_error_info_;
   GURL validated_url_;
 
   DISALLOW_COPY_AND_ASSIGN(LoadFailObserver);
@@ -85,6 +92,7 @@
     ui_test_utils::NavigateToURL(browser(), url);
     EXPECT_TRUE(observer.failed_load());
     EXPECT_EQ(net::ERR_NOT_IMPLEMENTED, observer.error_code());
+    EXPECT_EQ(net::ERR_NOT_IMPLEMENTED, observer.resolve_error_info().error);
     EXPECT_EQ(url, observer.validated_url());
   }
 }
diff --git a/chrome/test/data/local_ntp/local_ntp_browsertest.html b/chrome/test/data/local_ntp/local_ntp_browsertest.html
index 610bff72..d8a1fb6 100644
--- a/chrome/test/data/local_ntp/local_ntp_browsertest.html
+++ b/chrome/test/data/local_ntp/local_ntp_browsertest.html
@@ -70,7 +70,8 @@
 
       <div id="realbox-container">
         <div id="realbox-input-wrapper">
-          <div id="realbox-icon" class="search-icon"></div>
+          <div id="realbox-icon" class="search-icon"
+              data-realbox-icon-class="search-icon"></div>
           <input id="realbox" type="search" autocomplete="off"
               spellcheck="false" autofocus>
           <button id="realbox-microphone" class="microphone-icon" hidden>
diff --git a/chrome/test/data/local_ntp/realbox_browsertest.js b/chrome/test/data/local_ntp/realbox_browsertest.js
index 2e25b831..f2bd877 100644
--- a/chrome/test/data/local_ntp/realbox_browsertest.js
+++ b/chrome/test/data/local_ntp/realbox_browsertest.js
@@ -27,6 +27,7 @@
  * @const
  */
 test.realbox.CLASSES = {
+  CLOCK_ICON: 'clock-icon',
   HAS_IMAGE: 'has-image',
   IMAGE_CONTAINER: 'image-container',
   MATCH_IMAGE: 'match-image',
@@ -1261,13 +1262,14 @@
     matches: [
       test.realbox.getUrlMatch({allowedToBeDefaultMatch: true}),
       test.realbox.getSearchMatch(),
+      test.realbox.getSearchMatch({type: 'search-history'}),
     ],
   });
   assertTrue(test.realbox.areMatchesShowing());
 
   // First URL match should be showing and the favicon should be in the realbox.
   const matchEls = $(test.realbox.IDS.REALBOX_MATCHES).children;
-  assertEquals(2, matchEls.length);
+  assertEquals(3, matchEls.length);
   assertTrue(matchEls[0].classList.contains(test.realbox.CLASSES.SELECTED));
   assertTrue(!!realboxIcon.style.backgroundImage);
 
@@ -1283,6 +1285,12 @@
   assertTrue(matchEls[1].classList.contains(test.realbox.CLASSES.SELECTED));
   assertFalse(!!realboxIcon.style.backgroundImage);
 
+  test.realbox.realboxEl.dispatchEvent(arrowDown);
+
+  // Third search match should change to clock icon.
+  assertTrue(matchEls[2].classList.contains(test.realbox.CLASSES.SELECTED));
+  assertEquals(realboxIcon.className, test.realbox.CLASSES.CLOCK_ICON);
+
   const escapeToDefaultMatch = new KeyboardEvent('keydown', {
     bubbles: true,
     cancelable: true,
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn
index bff07dc7..93bad1ff 100644
--- a/chrome/test/data/webui/BUILD.gn
+++ b/chrome/test/data/webui/BUILD.gn
@@ -35,7 +35,6 @@
     "//chrome/browser/ui",
   ]
   data = [
-    "$root_gen_dir/chrome/test/data/webui/cr_focus_row_behavior_test.m.js",
     "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_action_menu_test.m.js",
     "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_checkbox_test.m.js",
     "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_expand_button_focus_tests.m.js",
@@ -44,8 +43,9 @@
     "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_tabs_test.m.js",
     "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_toggle_test.m.js",
     "$root_gen_dir/chrome/test/data/webui/cr_elements/iron_list_focus_test.m.js",
-    "$root_gen_dir/chrome/test/data/webui/test_browser_proxy.m.js",
+    "$root_gen_dir/chrome/test/data/webui/cr_focus_row_behavior_test.m.js",
     "$root_gen_dir/chrome/test/data/webui/mock_controller.m.js",
+    "$root_gen_dir/chrome/test/data/webui/test_browser_proxy.m.js",
     "$root_gen_dir/chrome/test/data/webui/test_store.m.js",
     "$root_gen_dir/chrome/test/data/webui/test_util.m.js",
   ]
@@ -185,12 +185,14 @@
     "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_icon_button_tests.m.js",
     "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_lazy_render_tests.m.js",
     "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_link_row_tests.m.js",
+    "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_policy_indicator_behavior_tests.m.js",
+    "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_policy_indicator_tests.m.js",
     "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_radio_button_test.m.js",
     "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_radio_group_test.m.js",
     "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_search_field_tests.m.js",
     "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_slider_test.m.js",
-    "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_toast_test.m.js",
     "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_toast_manager_test.m.js",
+    "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_toast_test.m.js",
     "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_toolbar_search_field_tests.m.js",
     "$root_gen_dir/chrome/test/data/webui/cr_elements/cr_view_manager_test.m.js",
     "$root_gen_dir/chrome/test/data/webui/fake_chrome_event.m.js",
diff --git a/chrome/test/data/webui/settings/certificate_manager_test.js b/chrome/test/data/webui/cr_components/certificate_manager_test.js
similarity index 99%
rename from chrome/test/data/webui/settings/certificate_manager_test.js
rename to chrome/test/data/webui/cr_components/certificate_manager_test.js
index 6b982671..935cf64 100644
--- a/chrome/test/data/webui/settings/certificate_manager_test.js
+++ b/chrome/test/data/webui/cr_components/certificate_manager_test.js
@@ -888,7 +888,6 @@
         });
       });
     }
-
   });
 
   suite('CertificateListTests', function() {
diff --git a/chrome/test/data/webui/cr_components/cr_components_browsertest.js b/chrome/test/data/webui/cr_components/cr_components_browsertest.js
index b9d47ec..f0c046c 100644
--- a/chrome/test/data/webui/cr_components/cr_components_browsertest.js
+++ b/chrome/test/data/webui/cr_components/cr_components_browsertest.js
@@ -96,3 +96,39 @@
 });
 
 GEN('#endif');
+
+GEN('#if defined(USE_NSS_CERTS)');
+
+/**
+ * Test fixture for chrome://settings/certificates. This tests the
+ * certificate-manager component in the context of the Settings privacy page.
+ * @constructor
+ * @extends {CrComponentsBrowserTest}
+ */
+function CrComponentsCertificateManagerTest() {}
+
+CrComponentsCertificateManagerTest.prototype = {
+  __proto__: CrComponentsBrowserTest.prototype,
+
+  /**
+   * Using the certificate-manager instance within
+   * chrome://settings/privacy_page for these tests, so that all strings are
+   * properly defined.
+   * @override
+   */
+  browsePreload: 'chrome://settings/privacy_page/privacy_page.html',
+
+  /** @override */
+  extraLibraries: CrComponentsBrowserTest.prototype.extraLibraries.concat([
+    '../test_util.js',
+    '../test_browser_proxy.js',
+    '../settings/ensure_lazy_loaded.js',
+    'certificate_manager_test.js',
+  ]),
+};
+
+TEST_F('CrComponentsCertificateManagerTest', 'All', function() {
+  mocha.run();
+});
+
+GEN('#endif  // defined(USE_NSS_CERTS)');
diff --git a/chrome/test/data/webui/cr_elements/BUILD.gn b/chrome/test/data/webui/cr_elements/BUILD.gn
index 9e1dfa52..ab0180d 100644
--- a/chrome/test/data/webui/cr_elements/BUILD.gn
+++ b/chrome/test/data/webui/cr_elements/BUILD.gn
@@ -19,6 +19,8 @@
     "cr_input_test.js",
     "cr_lazy_render_tests.js",
     "cr_link_row_tests.js",
+    "cr_policy_indicator_tests.js",
+    "cr_policy_indicator_behavior_tests.js",
     "cr_radio_button_test.js",
     "cr_radio_group_test.js",
     "cr_search_field_tests.js",
diff --git a/chrome/test/data/webui/cr_elements/cr_elements_v3_browsertest.js b/chrome/test/data/webui/cr_elements/cr_elements_v3_browsertest.js
index 9771c9d..260e1c6 100644
--- a/chrome/test/data/webui/cr_elements/cr_elements_v3_browsertest.js
+++ b/chrome/test/data/webui/cr_elements/cr_elements_v3_browsertest.js
@@ -255,3 +255,28 @@
 TEST_F('CrElementsViewManagerV3Test', 'All', function() {
   mocha.run();
 });
+
+// eslint-disable-next-line no-var
+var CrElementsPolicyIndicatorV3Test = class extends CrElementsV3BrowserTest {
+  /** @override */
+  get browsePreload() {
+    return 'chrome://test?module=cr_elements/cr_policy_indicator_tests.m.js';
+  }
+};
+
+TEST_F('CrElementsPolicyIndicatorV3Test', 'All', function() {
+  mocha.run();
+});
+
+// eslint-disable-next-line no-var
+var CrElementsPolicyIndicatorBehaviorV3Test =
+    class extends CrElementsV3BrowserTest {
+  /** @override */
+  get browsePreload() {
+    return 'chrome://test?module=cr_elements/cr_policy_indicator_behavior_tests.m.js';
+  }
+};
+
+TEST_F('CrElementsPolicyIndicatorBehaviorV3Test', 'All', function() {
+  mocha.run();
+});
diff --git a/chrome/test/data/webui/cr_elements/cr_policy_indicator_behavior_tests.js b/chrome/test/data/webui/cr_elements/cr_policy_indicator_behavior_tests.js
index 1689b4e..25ffe8f 100644
--- a/chrome/test/data/webui/cr_elements/cr_policy_indicator_behavior_tests.js
+++ b/chrome/test/data/webui/cr_elements/cr_policy_indicator_behavior_tests.js
@@ -3,6 +3,14 @@
 // found in the LICENSE file.
 
 /** @fileoverview Suite of tests for CrPolicyIndicatorBehavior. */
+
+// clang-format off
+// #import {CrPolicyIndicatorBehavior, CrPolicyIndicatorType} from 'chrome://resources/cr_elements/policy/cr_policy_indicator_behavior.m.js';
+// #import {Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+// #import {isChromeOS} from 'chrome://resources/js/cr.m.js';
+// #import 'chrome://test/cr_elements/cr_policy_strings.js';
+// clang-format on
+
 suite('CrPolicyIndicatorBehavior', function() {
   suiteSetup(function() {
     Polymer({
diff --git a/chrome/test/data/webui/cr_elements/cr_policy_indicator_tests.js b/chrome/test/data/webui/cr_elements/cr_policy_indicator_tests.js
index a3f2323..46e3655 100644
--- a/chrome/test/data/webui/cr_elements/cr_policy_indicator_tests.js
+++ b/chrome/test/data/webui/cr_elements/cr_policy_indicator_tests.js
@@ -2,6 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+// clang-format off
+// #import {CrPolicyIndicatorType} from 'chrome://resources/cr_elements/policy/cr_policy_indicator_behavior.m.js';
+// #import 'chrome://resources/cr_elements/policy/cr_policy_indicator.m.js';
+// #import {isChromeOS} from 'chrome://resources/js/cr.m.js';
+// #import 'chrome://test/cr_elements/cr_policy_strings.js';
+// clang-format on
+
 /** @fileoverview Suite of tests for cr-policy-indicator. */
 suite('CrPolicyIndicator', function() {
   /** @type {!CrPolicyIndicatorElement|undefined} */
diff --git a/chrome/test/data/webui/cr_elements/cr_policy_strings.js b/chrome/test/data/webui/cr_elements/cr_policy_strings.js
index 7e588ea..50151d82 100644
--- a/chrome/test/data/webui/cr_elements/cr_policy_strings.js
+++ b/chrome/test/data/webui/cr_elements/cr_policy_strings.js
@@ -16,3 +16,6 @@
   controlledSettingParent: 'parent',
   controlledSettingChildRestriction: 'Restricted for child',
 };
+
+// Necessary for tests residing within a JS module.
+window.CrPolicyStrings = CrPolicyStrings;
diff --git a/chrome/test/data/webui/cr_elements/cr_slider_test.js b/chrome/test/data/webui/cr_elements/cr_slider_test.js
index 80da6cc..a4ca150 100644
--- a/chrome/test/data/webui/cr_elements/cr_slider_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_slider_test.js
@@ -4,7 +4,7 @@
 
 // clang-format off
 // #import 'chrome://resources/cr_elements/cr_slider/cr_slider.m.js';
-// #import {Polymer, flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+// #import {flush} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
 // #import {flushTasks, eventToPromise} from '../test_util.m.js';
 // #import {pressAndReleaseKeyOn} from 'chrome://resources/polymer/v3_0/iron-test-helpers/mock-interactions.js';
 // clang-format on
@@ -14,7 +14,16 @@
 
   setup(function() {
     PolymerTest.clearBody();
-    document.body.innerHTML = '<cr-slider min="0" max="100"></cr-slider>';
+    document.body.innerHTML = `
+      <style>
+        #wrapper {
+          width: 200px;
+        }
+      </style>
+      <div id="wrapper">
+        <cr-slider min="0" max="100"></cr-slider>
+      </div>
+    `;
 
     crSlider = document.body.querySelector('cr-slider');
     crSlider.value = 0;
diff --git a/chrome/test/data/webui/settings/cr_settings_browsertest.js b/chrome/test/data/webui/settings/cr_settings_browsertest.js
index 41c59c8..c9c75d1 100644
--- a/chrome/test/data/webui/settings/cr_settings_browsertest.js
+++ b/chrome/test/data/webui/settings/cr_settings_browsertest.js
@@ -840,40 +840,6 @@
   mocha.run();
 });
 
-GEN('#if defined(USE_NSS_CERTS)');
-
-/**
- * Test fixture for chrome://settings/certificates. This tests the
- * certificate-manager component in the context of the Settings privacy page.
- * @constructor
- * @extends {CrSettingsBrowserTest}
- */
-function CrSettingsCertificateManagerTest() {}
-
-CrSettingsCertificateManagerTest.prototype = {
-  __proto__: CrSettingsBrowserTest.prototype,
-
-  /**
-   * The certificate-manager subpage is embedded in privacy_page.html.
-   * @override
-   */
-  browsePreload: 'chrome://settings/privacy_page/privacy_page.html',
-
-  /** @override */
-  extraLibraries: CrSettingsBrowserTest.prototype.extraLibraries.concat([
-    '../test_util.js',
-    '../test_browser_proxy.js',
-    'ensure_lazy_loaded.js',
-    'certificate_manager_test.js',
-  ]),
-};
-
-TEST_F('CrSettingsCertificateManagerTest', 'All', function() {
-  mocha.run();
-});
-
-GEN('#endif  // defined(USE_NSS_CERTS)');
-
 /**
  * Test fixture for
  * chrome/browser/resources/settings/privacy_page/personalization_options.html.
diff --git a/chrome/test/data/webui/settings/people_page_test.js b/chrome/test/data/webui/settings/people_page_test.js
index fba48d0..b9d7c0dc 100644
--- a/chrome/test/data/webui/settings/people_page_test.js
+++ b/chrome/test/data/webui/settings/people_page_test.js
@@ -17,14 +17,14 @@
     }
   }
 
-  suite('ProfileInfoTests', function() {
-    /** @type {SettingsPeoplePageElement} */
-    let peoplePage = null;
-    /** @type {settings.ProfileInfoBrowserProxy} */
-    let browserProxy = null;
-    /** @type {settings.SyncBrowserProxy} */
-    let syncBrowserProxy = null;
+  /** @type {?SettingsPeoplePageElement} */
+  let peoplePage = null;
+  /** @type {?settings.ProfileInfoBrowserProxy} */
+  let profileInfoBrowserProxy = null;
+  /** @type {?settings.SyncBrowserProxy} */
+  let syncBrowserProxy = null;
 
+  suite('ProfileInfoTests', function() {
     suiteSetup(function() {
       loadTimeData.overrideValues({
         // Force Dice off. Dice is tested in the DiceUITest suite.
@@ -39,8 +39,8 @@
     });
 
     setup(async function() {
-      browserProxy = new TestProfileInfoBrowserProxy();
-      settings.ProfileInfoBrowserProxyImpl.instance_ = browserProxy;
+      profileInfoBrowserProxy = new TestProfileInfoBrowserProxy();
+      settings.ProfileInfoBrowserProxyImpl.instance_ = profileInfoBrowserProxy;
 
       syncBrowserProxy = new TestSyncBrowserProxy();
       settings.SyncBrowserProxyImpl.instance_ = syncBrowserProxy;
@@ -51,7 +51,7 @@
       document.body.appendChild(peoplePage);
 
       await syncBrowserProxy.whenCalled('getSyncStatus');
-      await browserProxy.whenCalled('getProfileInfo');
+      await profileInfoBrowserProxy.whenCalled('getProfileInfo');
       Polymer.dom.flush();
     });
 
@@ -61,10 +61,10 @@
 
     test('GetProfileInfo', function() {
       assertEquals(
-          browserProxy.fakeProfileInfo.name,
+          profileInfoBrowserProxy.fakeProfileInfo.name,
           peoplePage.$$('#profile-name').textContent.trim());
       const bg = peoplePage.$$('#profile-icon').style.backgroundImage;
-      assertTrue(bg.includes(browserProxy.fakeProfileInfo.iconUrl));
+      assertTrue(bg.includes(profileInfoBrowserProxy.fakeProfileInfo.iconUrl));
 
       const iconDataUrl = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEA' +
           'LAAAAAABAAEAAAICTAEAOw==';
@@ -81,16 +81,9 @@
 
   if (!cr.isChromeOS) {
     suite('SyncStatusTests', function() {
-      /** @type {SettingsPeoplePageElement} */
-      let peoplePage = null;
-      /** @type {settings.SyncBrowserProxy} */
-      let browserProxy = null;
-      /** @type {settings.ProfileInfoBrowserProxy} */
-      let profileInfoBrowserProxy = null;
-
       setup(function() {
-        browserProxy = new TestSyncBrowserProxy();
-        settings.SyncBrowserProxyImpl.instance_ = browserProxy;
+        syncBrowserProxy = new TestSyncBrowserProxy();
+        settings.SyncBrowserProxyImpl.instance_ = syncBrowserProxy;
 
         profileInfoBrowserProxy = new TestProfileInfoBrowserProxy();
         settings.ProfileInfoBrowserProxyImpl.instance_ =
@@ -122,7 +115,7 @@
 
       test('GetProfileInfo', function() {
         let disconnectButton = null;
-        return browserProxy.whenCalled('getSyncStatus')
+        return syncBrowserProxy.whenCalled('getSyncStatus')
             .then(function() {
               Polymer.dom.flush();
               disconnectButton = peoplePage.$$('#disconnectButton');
@@ -154,7 +147,7 @@
               return popstatePromise;
             })
             .then(function() {
-              return browserProxy.whenCalled('signOut');
+              return syncBrowserProxy.whenCalled('signOut');
             })
             .then(function(deleteProfile) {
               assertFalse(deleteProfile);
@@ -182,7 +175,7 @@
               assertTrue(!!disconnectManagedProfileConfirm);
               assertFalse(disconnectManagedProfileConfirm.hidden);
 
-              browserProxy.resetResolver('signOut');
+              syncBrowserProxy.resetResolver('signOut');
 
               const popstatePromise = new Promise(function(resolve) {
                 listenOnce(window, 'popstate', resolve);
@@ -193,7 +186,7 @@
               return popstatePromise;
             })
             .then(function() {
-              return browserProxy.whenCalled('signOut');
+              return syncBrowserProxy.whenCalled('signOut');
             })
             .then(function(deleteProfile) {
               assertTrue(deleteProfile);
@@ -201,7 +194,7 @@
       });
 
       test('getProfileStatsCount', function() {
-        return browserProxy.whenCalled('getSyncStatus')
+        return syncBrowserProxy.whenCalled('getSyncStatus')
             .then(function() {
               Polymer.dom.flush();
 
@@ -279,7 +272,7 @@
       });
 
       test('Signout dialog suppressed when not signed in', function() {
-        return browserProxy.whenCalled('getSyncStatus')
+        return syncBrowserProxy.whenCalled('getSyncStatus')
             .then(function() {
               settings.Router.getInstance().navigateTo(
                   settings.routes.SIGN_OUT);
@@ -315,13 +308,6 @@
     });
 
     suite('DiceUITest', function() {
-      /** @type {SettingsPeoplePageElement} */
-      let peoplePage = null;
-      /** @type {settings.SyncBrowserProxy} */
-      let browserProxy = null;
-      /** @type {settings.ProfileInfoBrowserProxy} */
-      let profileInfoBrowserProxy = null;
-
       suiteSetup(function() {
         // Force UIs to think DICE is enabled for this profile.
         loadTimeData.overrideValues({
@@ -330,8 +316,8 @@
       });
 
       setup(function() {
-        browserProxy = new TestSyncBrowserProxy();
-        settings.SyncBrowserProxyImpl.instance_ = browserProxy;
+        syncBrowserProxy = new TestSyncBrowserProxy();
+        settings.SyncBrowserProxyImpl.instance_ = syncBrowserProxy;
 
         profileInfoBrowserProxy = new TestProfileInfoBrowserProxy();
         settings.ProfileInfoBrowserProxyImpl.instance_ =
@@ -350,7 +336,7 @@
       });
 
       test('ShowCorrectRows', function() {
-        return browserProxy.whenCalled('getSyncStatus').then(function() {
+        return syncBrowserProxy.whenCalled('getSyncStatus').then(function() {
           // The correct /manageProfile link row is shown.
           assertTrue(!!peoplePage.$$('#edit-profile'));
           assertFalse(!!peoplePage.$$('#picture-subpage-trigger'));
@@ -455,16 +441,9 @@
   }
 
   suite('SyncSettings', function() {
-    /** @type {SettingsPeoplePageElement} */
-    let peoplePage = null;
-    /** @type {settings.SyncBrowserProxy} */
-    let browserProxy = null;
-    /** @type {settings.ProfileInfoBrowserProxy} */
-    let profileInfoBrowserProxy = null;
-
     setup(async function() {
-      browserProxy = new TestSyncBrowserProxy();
-      settings.SyncBrowserProxyImpl.instance_ = browserProxy;
+      syncBrowserProxy = new TestSyncBrowserProxy();
+      settings.SyncBrowserProxyImpl.instance_ = syncBrowserProxy;
 
       profileInfoBrowserProxy = new TestProfileInfoBrowserProxy();
       settings.ProfileInfoBrowserProxyImpl.instance_ = profileInfoBrowserProxy;
@@ -474,7 +453,7 @@
       peoplePage.pageVisibility = settings.pageVisibility;
       document.body.appendChild(peoplePage);
 
-      await browserProxy.whenCalled('getSyncStatus');
+      await syncBrowserProxy.whenCalled('getSyncStatus');
       Polymer.dom.flush();
     });
 
@@ -550,16 +529,22 @@
       }
     }
 
-    suite('Chrome OS', function() {
-      /** @type {SettingsPeoplePageElement} */
-      let peoplePage = null;
-      /** @type {settings.SyncBrowserProxy} */
-      let browserProxy = null;
-      /** @type {settings.ProfileInfoBrowserProxy} */
-      let profileInfoBrowserProxy = null;
-      /** @type {settings.AccountManagerBrowserProxy} */
-      let accountManagerBrowserProxy = null;
+    /** @type {?settings.AccountManagerBrowserProxy} */
+    let accountManagerBrowserProxy = null;
 
+    // Preferences should exist for embedded 'personalization_options.html'.
+    // We don't perform tests on them.
+    const DEFAULT_PREFS = {
+      profile: {password_manager_leak_detection: {value: true}},
+      signin: {
+        allowed_on_next_startup:
+            {type: chrome.settingsPrivate.PrefType.BOOLEAN, value: true}
+      },
+      safebrowsing:
+          {enabled: {value: true}, scout_reporting_enabled: {value: true}},
+    };
+
+    suite('Chrome OS', function() {
       suiteSetup(function() {
         loadTimeData.overrideValues({
           // Simulate SplitSettings (OS settings in their own surface).
@@ -570,8 +555,8 @@
       });
 
       setup(async function() {
-        browserProxy = new TestSyncBrowserProxy();
-        settings.SyncBrowserProxyImpl.instance_ = browserProxy;
+        syncBrowserProxy = new TestSyncBrowserProxy();
+        settings.SyncBrowserProxyImpl.instance_ = syncBrowserProxy;
 
         profileInfoBrowserProxy = new TestProfileInfoBrowserProxy();
         settings.ProfileInfoBrowserProxyImpl.instance_ =
@@ -583,18 +568,12 @@
 
         PolymerTest.clearBody();
         peoplePage = document.createElement('settings-people-page');
-        // Preferences should exist for embedded 'personalization_options.html'.
-        // We don't perform tests on them.
-        peoplePage.prefs = {
-          profile: {password_manager_leak_detection: {value: true}},
-          safebrowsing:
-              {enabled: {value: true}, scout_reporting_enabled: {value: true}},
-        };
+        peoplePage.prefs = DEFAULT_PREFS;
         peoplePage.pageVisibility = settings.pageVisibility;
         document.body.appendChild(peoplePage);
 
         await accountManagerBrowserProxy.whenCalled('getAccounts');
-        await browserProxy.whenCalled('getSyncStatus');
+        await syncBrowserProxy.whenCalled('getSyncStatus');
         Polymer.dom.flush();
       });
 
@@ -628,10 +607,6 @@
     });
 
     suite('Chrome OS with account manager disabled', function() {
-      let peoplePage = null;
-      let syncBrowserProxy = null;
-      let profileInfoBrowserProxy = null;
-
       suiteSetup(function() {
         loadTimeData.overrideValues({
           // Simulate SplitSettings (OS settings in their own surface).
@@ -651,13 +626,7 @@
 
         PolymerTest.clearBody();
         peoplePage = document.createElement('settings-people-page');
-        // Preferences should exist for embedded 'personalization_options.html'.
-        // We don't perform tests on them.
-        peoplePage.prefs = {
-          profile: {password_manager_leak_detection: {value: true}},
-          safebrowsing:
-              {enabled: {value: true}, scout_reporting_enabled: {value: true}},
-        };
+        peoplePage.prefs = DEFAULT_PREFS;
         peoplePage.pageVisibility = settings.pageVisibility;
         document.body.appendChild(peoplePage);
 
@@ -689,5 +658,51 @@
         assertEquals(oldRoute, settings.Router.getInstance().getCurrentRoute());
       });
     });
+
+    suite('Chrome OS with SplitSettingsSync', function() {
+      suiteSetup(function() {
+        loadTimeData.overrideValues({
+          splitSettingsSyncEnabled: true,
+        });
+      });
+
+      setup(async function() {
+        syncBrowserProxy = new TestSyncBrowserProxy();
+        settings.SyncBrowserProxyImpl.instance_ = syncBrowserProxy;
+
+        profileInfoBrowserProxy = new TestProfileInfoBrowserProxy();
+        settings.ProfileInfoBrowserProxyImpl.instance_ =
+            profileInfoBrowserProxy;
+
+        PolymerTest.clearBody();
+        peoplePage = document.createElement('settings-people-page');
+        peoplePage.prefs = DEFAULT_PREFS;
+        peoplePage.pageVisibility = settings.pageVisibility;
+        document.body.appendChild(peoplePage);
+
+        await syncBrowserProxy.whenCalled('getSyncStatus');
+        Polymer.dom.flush();
+      });
+
+      teardown(function() {
+        peoplePage.remove();
+      });
+
+      test('Sync account control is shown', () => {
+        sync_test_util.simulateSyncStatus({
+          signinAllowed: true,
+          syncSystemEnabled: true,
+        });
+
+        // Account control is visible.
+        const accountControl = peoplePage.$$('settings-sync-account-control');
+        assertNotEquals(
+            'none', window.getComputedStyle(accountControl).display);
+
+        // Profile row items are not available.
+        assertFalse(!!peoplePage.$$('#profile-icon'));
+        assertFalse(!!peoplePage.$$('#profile-row'));
+      });
+    });
   }
 });
diff --git a/chrome/test/ppapi/ppapi_browsertest.cc b/chrome/test/ppapi/ppapi_browsertest.cc
index 7bc18b97..66ac32f 100644
--- a/chrome/test/ppapi/ppapi_browsertest.cc
+++ b/chrome/test/ppapi/ppapi_browsertest.cc
@@ -1313,7 +1313,7 @@
   network::DnsLookupResult result2 =
       network::BlockingDnsLookup(network_context, kHostPortPair,
                                  std::move(params), net::NetworkIsolationKey());
-  EXPECT_EQ(net::ERR_DNS_CACHE_MISS, result2.error);
+  EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, result2.error);
 }
 
 // HostResolver and HostResolverPrivate tests. The PPAPI code used by these
diff --git a/chromeos/components/quick_answers/quick_answers_client.cc b/chromeos/components/quick_answers/quick_answers_client.cc
index 9e36d11..d0c1b54 100644
--- a/chromeos/components/quick_answers/quick_answers_client.cc
+++ b/chromeos/components/quick_answers/quick_answers_client.cc
@@ -46,13 +46,16 @@
     : url_loader_factory_(url_loader_factory),
       assistant_state_(assistant_state),
       delegate_(delegate) {
-  // We observe Assistant state to detect enabling/disabling of Assistant in
-  // settings as well as enabling/disabling of screen context.
-  assistant_state_->AddObserver(this);
+  if (assistant_state_) {
+    // We observe Assistant state to detect enabling/disabling of Assistant in
+    // settings as well as enabling/disabling of screen context.
+    assistant_state_->AddObserver(this);
+  }
 }
 
 QuickAnswersClient::~QuickAnswersClient() {
-  assistant_state_->RemoveObserver(this);
+  if (assistant_state_)
+    assistant_state_->RemoveObserver(this);
 }
 
 void QuickAnswersClient::OnAssistantFeatureAllowedChanged(
@@ -79,6 +82,10 @@
   NotifyEligibilityChanged();
 }
 
+void QuickAnswersClient::OnAssistantStateDestroyed() {
+  assistant_state_ = nullptr;
+}
+
 void QuickAnswersClient::SendRequest(
     const QuickAnswersRequest& quick_answers_request) {
   // Preprocess the request.
@@ -96,8 +103,8 @@
 void QuickAnswersClient::NotifyEligibilityChanged() {
   DCHECK(delegate_);
   bool is_eligible =
-      (chromeos::features::IsQuickAnswersEnabled() && assistant_enabled_ &&
-       locale_supported_ && assistant_context_enabled_ &&
+      (chromeos::features::IsQuickAnswersEnabled() && assistant_state_ &&
+       assistant_enabled_ && locale_supported_ && assistant_context_enabled_ &&
        assistant_allowed_state_ == ash::mojom::AssistantAllowedState::ALLOWED);
 
   if (is_eligible_ != is_eligible) {
diff --git a/chromeos/components/quick_answers/quick_answers_client.h b/chromeos/components/quick_answers/quick_answers_client.h
index 77b373b..dbcc3e1 100644
--- a/chromeos/components/quick_answers/quick_answers_client.h
+++ b/chromeos/components/quick_answers/quick_answers_client.h
@@ -64,9 +64,10 @@
   void OnAssistantSettingsEnabled(bool enabled) override;
   void OnAssistantContextEnabled(bool enabled) override;
   void OnLocaleChanged(const std::string& locale) override;
+  void OnAssistantStateDestroyed() override;
 
-  // Send a quick answer request.
-  void SendRequest(const QuickAnswersRequest& quick_answers_request);
+  // Send a quick answer request. Virtual for testing.
+  virtual void SendRequest(const QuickAnswersRequest& quick_answers_request);
 
  private:
   void OnQuickAnswerReceived(std::unique_ptr<QuickAnswer> quick_answer);
diff --git a/chromeos/network/OWNERS b/chromeos/network/OWNERS
index 7ac9225..8c9e09c 100644
--- a/chromeos/network/OWNERS
+++ b/chromeos/network/OWNERS
@@ -1,4 +1,5 @@
+azeemarshad@chromium.org
 khorimoto@chromium.org
 stevenjb@chromium.org
 tbarzic@chromium.org
-# COMPONENT: OS>Systems>Network
+# COMPONENT: UI>Shell>Networking
diff --git a/chromeos/services/machine_learning/public/mojom/graph_executor.mojom b/chromeos/services/machine_learning/public/mojom/graph_executor.mojom
index 42d5c04..be84ea0 100644
--- a/chromeos/services/machine_learning/public/mojom/graph_executor.mojom
+++ b/chromeos/services/machine_learning/public/mojom/graph_executor.mojom
@@ -28,8 +28,6 @@
   UNKNOWN_OUTPUT_ERROR = 7,
   DUPLICATE_OUTPUT_ERROR = 8,
   EXECUTION_ERROR = 9,
-  // Remove kMax and use builtin kMaxValue after Mojo uprev (crbug.com/909719).
-  kMax = EXECUTION_ERROR,
 };
 
 // API for performing inference on a TensorFlow graph. A given graph can be
diff --git a/chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom b/chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom
index 745ad0f4..2e24676 100644
--- a/chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom
+++ b/chromeos/services/machine_learning/public/mojom/machine_learning_service.mojom
@@ -23,8 +23,6 @@
   OK = 0,
   MODEL_SPEC_ERROR = 1,
   LOAD_MODEL_ERROR = 2,
-  // Remove kMax and use builtin kMaxValue after Mojo uprev (crbug.com/909719).
-  kMax = LOAD_MODEL_ERROR,
 };
 
 // Top-level interface between Chromium and the ML Service daemon.
diff --git a/chromeos/services/machine_learning/public/mojom/model.mojom b/chromeos/services/machine_learning/public/mojom/model.mojom
index 2b48d7a..ea9b891 100644
--- a/chromeos/services/machine_learning/public/mojom/model.mojom
+++ b/chromeos/services/machine_learning/public/mojom/model.mojom
@@ -44,8 +44,6 @@
   OK = 0,
   MODEL_INTERPRETATION_ERROR = 1,
   MEMORY_ALLOCATION_ERROR = 2,
-  // Remove kMax and use builtin kMaxValue after Mojo uprev (crbug.com/909719).
-  kMax = MEMORY_ALLOCATION_ERROR,
 };
 
 // Model specification for builtin models.
diff --git a/components/cronet/stale_host_resolver.cc b/components/cronet/stale_host_resolver.cc
index 5097042..58fb0c8 100644
--- a/components/cronet/stale_host_resolver.cc
+++ b/components/cronet/stale_host_resolver.cc
@@ -216,8 +216,10 @@
   cache_parameters.source = net::HostResolverSource::LOCAL_ONLY;
   cache_request_ = resolver_->inner_resolver_->CreateRequest(
       host_, network_isolation_key_, net_log_, cache_parameters);
-  cache_error_ =
+  int error =
       cache_request_->Start(base::BindOnce([](int error) { NOTREACHED(); }));
+  DCHECK_NE(net::ERR_IO_PENDING, error);
+  cache_error_ = cache_request_->GetResolveErrorInfo().error;
   DCHECK_NE(net::ERR_IO_PENDING, cache_error_);
   // If it's a fresh cache hit (or literal), return it synchronously.
   if (cache_error_ != net::ERR_DNS_CACHE_MISS &&
diff --git a/components/exo/surface_tree_host.cc b/components/exo/surface_tree_host.cc
index 6cb904b..ef1a76a 100644
--- a/components/exo/surface_tree_host.cc
+++ b/components/exo/surface_tree_host.cc
@@ -9,6 +9,8 @@
 #include "base/macros.h"
 #include "cc/trees/layer_tree_frame_sink.h"
 #include "components/exo/layer_tree_frame_sink_holder.h"
+#include "components/exo/shell_surface_base.h"
+#include "components/exo/shell_surface_util.h"
 #include "components/exo/surface.h"
 #include "components/exo/wm_helper.h"
 #include "components/viz/common/quads/compositor_frame.h"
@@ -17,6 +19,7 @@
 #include "components/viz/common/quads/solid_color_draw_quad.h"
 #include "gpu/command_buffer/client/gles2_interface.h"
 #include "third_party/skia/include/core/SkPath.h"
+#include "ui/aura/client/aura_constants.h"
 #include "ui/aura/env.h"
 #include "ui/aura/window.h"
 #include "ui/aura/window_delegate.h"
@@ -212,6 +215,21 @@
 void SurfaceTreeHost::SubmitCompositorFrame() {
   viz::CompositorFrame frame = PrepareToSubmitCompositorFrame();
 
+  // TODO(1041932,1034876): Remove or early return once these issues
+  // are fixed or identified.
+  if (frame.size_in_pixels().IsEmpty()) {
+    aura::Window* toplevel = root_surface_->window()->GetToplevelWindow();
+    auto app_type = toplevel->GetProperty(aura::client::kAppType);
+    const std::string* app_id = GetShellApplicationId(toplevel);
+    const std::string* startup_id = GetShellStartupId(toplevel);
+    auto* shell_surface = GetShellSurfaceBaseForWindow(toplevel);
+    DCHECK(!frame.size_in_pixels().IsEmpty())
+        << " Title=" << shell_surface->GetWindowTitle()
+        << ", AppType=" << static_cast<int>(app_type)
+        << ", AppId=" << (app_id ? *app_id : "''")
+        << ", StartupId=" << (startup_id ? *startup_id : "''");
+  }
+
   root_surface_->AppendSurfaceHierarchyCallbacks(&frame_callbacks_,
                                                  &presentation_callbacks_);
   if (!presentation_callbacks_.empty()) {
diff --git a/components/metrics/structured/BUILD.gn b/components/metrics/structured/BUILD.gn
index 3cddbd9..6abb879 100644
--- a/components/metrics/structured/BUILD.gn
+++ b/components/metrics/structured/BUILD.gn
@@ -10,6 +10,8 @@
   sources = [
     "event_base.cc",
     "event_base.h",
+    "key_data.cc",
+    "key_data.h",
     "recorder.cc",
     "recorder.h",
     "structured_metrics_provider.cc",
@@ -22,13 +24,17 @@
     "//base",
     "//components/metrics",
     "//components/prefs",
+    "//crypto",
     "//tools/metrics/structured:structured_events",
   ]
 }
 
 source_set("unit_tests") {
   testonly = true
-  sources = [ "structured_metrics_provider_unittest.cc" ]
+  sources = [
+    "key_data_unittest.cc",
+    "structured_metrics_provider_unittest.cc",
+  ]
 
   deps = [
     ":structured",
diff --git a/components/metrics/structured/DEPS b/components/metrics/structured/DEPS
index 6f3255b4..1f172b2 100644
--- a/components/metrics/structured/DEPS
+++ b/components/metrics/structured/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
   "+components/metrics",
   "+components/prefs",
+  "+tools/metrics/structured",
 ]
diff --git a/components/metrics/structured/key_data.cc b/components/metrics/structured/key_data.cc
new file mode 100644
index 0000000..539c0a52
--- /dev/null
+++ b/components/metrics/structured/key_data.cc
@@ -0,0 +1,193 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/metrics/structured/key_data.h"
+
+#include <memory>
+
+#include "base/rand_util.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/time/time.h"
+#include "base/unguessable_token.h"
+#include "base/values.h"
+#include "components/prefs/json_pref_store.h"
+#include "crypto/hmac.h"
+#include "crypto/sha2.h"
+#include "tools/metrics/structured/structured_events.h"
+
+namespace metrics {
+namespace structured {
+namespace internal {
+namespace {
+
+// The expected size of a key, in bytes.
+constexpr size_t kKeySize = 32;
+
+// The default maximum number of days before rotating keys.
+constexpr size_t kDefaultRotationPeriod = 90;
+
+// Generates a key, which is the string representation of
+// base::UnguessableToken, and is of size |kKeySize| bytes.
+std::string GenerateKey() {
+  const std::string key = base::UnguessableToken::Create().ToString();
+  DCHECK_EQ(key.size(), kKeySize);
+  return key;
+}
+
+std::string HashToHex(const uint64_t hash) {
+  return base::HexEncode(&hash, sizeof(uint64_t));
+}
+
+std::string KeyPath(const uint64_t event) {
+  return base::StrCat({"keys.", base::NumberToString(event), ".key"});
+}
+
+std::string LastRotationPath(const uint64_t event) {
+  return base::StrCat({"keys.", base::NumberToString(event), ".last_rotation"});
+}
+
+std::string RotationPeriodPath(const uint64_t event) {
+  return base::StrCat(
+      {"keys.", base::NumberToString(event), ".rotation_period"});
+}
+
+}  // namespace
+
+KeyData::KeyData(JsonPrefStore* key_store) : key_store_(key_store) {
+  DCHECK(key_store_);
+  ValidateKeys();
+}
+
+KeyData::~KeyData() = default;
+
+base::Optional<std::string> KeyData::ValidateAndGetKey(const uint64_t event) {
+  DCHECK(key_store_);
+  const int now = (base::Time::Now() - base::Time::UnixEpoch()).InDays();
+
+  // If the key for |key_path| doesn't exist, initialize new key data. Set the
+  // last rotation to a uniformly selected day between today and
+  // |kDefaultRotationPeriod| days ago, to uniformly distribute users amongst
+  // rotation cohorts.
+  if (!key_store_->GetValue(KeyPath(event), nullptr)) {
+    const int rotation_seed = base::RandInt(0, kDefaultRotationPeriod - 1);
+    SetRotationPeriod(event, kDefaultRotationPeriod);
+    SetLastRotation(event, now - rotation_seed);
+    SetKey(event, GenerateKey());
+  }
+
+  // If the key for |event| is outdated, generate a new key and write it to
+  // the |keys| pref store along with updated rotation data. Update the last
+  // rotation such that the user stays in the same cohort.
+  const int rotation_period = GetRotationPeriod(event);
+  const int last_rotation = GetLastRotation(event);
+  if (now - last_rotation > rotation_period) {
+    const int new_last_rotation = now - (now - last_rotation) % rotation_period;
+    SetLastRotation(event, new_last_rotation);
+    SetKey(event, GenerateKey());
+  }
+
+  const base::Value* key_json;
+  if (!(key_store_->GetValue(KeyPath(event), &key_json) &&
+        key_json->is_string())) {
+    // TODO(crbug.com/1016655): log an error to UMA.
+    return base::nullopt;
+  }
+
+  const std::string key = key_json->GetString();
+  if (key.size() != kKeySize) {
+    // TODO(crbug.com/1016655): log an error to UMA.
+    return base::nullopt;
+  }
+
+  return key;
+}
+
+void KeyData::ValidateKeys() {
+  for (const uint64_t event : metrics::structured::events::kEventNameHashes) {
+    ValidateAndGetKey(event);
+  }
+}
+
+void KeyData::SetLastRotation(const uint64_t event, const int last_rotation) {
+  return key_store_->SetValue(LastRotationPath(event),
+                              std::make_unique<base::Value>(last_rotation),
+                              WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+}
+
+void KeyData::SetRotationPeriod(const uint64_t event,
+                                const int rotation_period) {
+  return key_store_->SetValue(RotationPeriodPath(event),
+                              std::make_unique<base::Value>(rotation_period),
+                              WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+}
+
+void KeyData::SetKey(const uint64_t event, const std::string& key) {
+  return key_store_->SetValue(KeyPath(event),
+                              std::make_unique<base::Value>(key),
+                              WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+}
+
+int KeyData::GetLastRotation(const uint64_t event) {
+  const base::Value* value;
+  if (!(key_store_->GetValue(LastRotationPath(event), &value) &&
+        value->is_int())) {
+    // TODO(crbug.com/1016655): log an error to UMA.
+    DCHECK(false);
+    return 0u;
+  }
+  return value->GetInt();
+}
+
+int KeyData::GetRotationPeriod(const uint64_t event) {
+  const base::Value* value;
+  if (!(key_store_->GetValue(RotationPeriodPath(event), &value) &&
+        value->is_int())) {
+    // TODO(crbug.com/1016655): log an error to UMA.
+    DCHECK(false);
+    return 0u;
+  }
+  return value->GetInt();
+}
+
+uint64_t KeyData::UserEventId(const uint64_t event) {
+  // Retrieve the key for |event|.
+  const base::Optional<std::string> key = ValidateAndGetKey(event);
+  if (!key) {
+    // TODO(crbug.com/1016655): log an error to UMA.
+    return 0u;
+  }
+
+  // Compute and return the hash.
+  uint64_t hash;
+  crypto::SHA256HashString(key.value(), &hash, sizeof(uint64_t));
+  return hash;
+}
+
+uint64_t KeyData::HashForEventMetric(const uint64_t event,
+                                     const uint64_t metric,
+                                     const std::string& value) {
+  // Retrieve the key for |event|.
+  const base::Optional<std::string> key = ValidateAndGetKey(event);
+  if (!key) {
+    // TODO(crbug.com/1016655): log an error to UMA.
+    DCHECK(false);
+    return 0u;
+  }
+
+  // Initialize the HMAC.
+  crypto::HMAC hmac(crypto::HMAC::HashAlgorithm::SHA256);
+  CHECK(hmac.Init(key.value()));
+
+  // Compute and return the digest.
+  const std::string salted_value = base::StrCat({HashToHex(metric), value});
+  uint64_t digest;
+  CHECK(hmac.Sign(salted_value, reinterpret_cast<uint8_t*>(&digest),
+                  sizeof(digest)));
+  return digest;
+}
+
+}  // namespace internal
+}  // namespace structured
+}  // namespace metrics
diff --git a/components/metrics/structured/key_data.h b/components/metrics/structured/key_data.h
new file mode 100644
index 0000000..90497ced
--- /dev/null
+++ b/components/metrics/structured/key_data.h
@@ -0,0 +1,115 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_METRICS_STRUCTURED_KEY_DATA_H_
+#define COMPONENTS_METRICS_STRUCTURED_KEY_DATA_H_
+
+#include <string>
+
+#include "base/optional.h"
+
+class JsonPrefStore;
+
+namespace metrics {
+namespace structured {
+namespace internal {
+
+// KeyData is the central class for managing keys and generating hashes for
+// structured metrics.
+//
+// The class maintains one key and its rotation data for every event defined
+// in /tools/metrics/structured.xml. This can be used to generate:
+//  - a user ID for the event with KeyData::UserEventId.
+//  - a hash of a given value for the event with KeyData::Hash.
+//
+// KeyData performs key rotation. Every event is associated with a rotation
+// period, which is 90 days unless specified in structured.xml. Keys are rotated
+// with a resolution of one day. They are guaranteed not to be used for Hash or
+// UserEventId for longer than their rotation period, except in cases of local
+// clock changes.
+//
+// When first created, every event's key rotation date is selected uniformly so
+// that there is an even distribution of rotations across users. This means
+// that, for most users, the first rotation period will be shorter than the
+// standard full rotation period for that event.
+//
+// Key storage is backed by a JsonPrefStore which is passed to the ctor and must
+// outlive the KeyData instance. Within the pref store, each event has three
+// pieces of associated data:
+//  - the rotation period for this event in days.
+//  - the day of the last key rotation, as a day since the unix epoch.
+//  - the key itself.
+//
+// This is stored in the structure:
+//   keys.{event_name_hash}.rotation_period
+//                         .last_rotation
+//                         .key
+//
+// TODO(crbug.com/1016655): log UMA error metrics
+// TODO(crbug.com/1016655): add ability to override default rotation period
+class KeyData {
+ public:
+  explicit KeyData(JsonPrefStore* key_store);
+  ~KeyData();
+
+  KeyData(const KeyData&) = delete;
+  KeyData& operator=(const KeyData&) = delete;
+
+  // Returns a digest of |value| for |metric| in the context of |event|.
+  // Terminology: a metric is a (name, value) pair, and an event is a bundle of
+  // metrics.
+  //
+  //  - |event| is the uint64 name hash of an event.
+  //  - |metric| is the uint64 name hash of a metric within |event|.
+  //  - |value| is the string value to hash.
+  //
+  // The result is the HMAC digest of the |value| salted with |metric|, using
+  // the key for |event|. That is:
+  //
+  //   HMAC_SHA256(key(event), concat(value, hex(metric)))
+  //
+  // Returns 0u in case of an error.
+  uint64_t HashForEventMetric(uint64_t event,
+                              uint64_t metric,
+                              const std::string& value);
+
+  // Returns an ID for this (user, |event|) pair. |event| is the name of an
+  // event, represented by the first 8 bytes of the MD5 hash of its name defined
+  // in structured.xml.
+  //
+  // The derived ID is the first 8 bytes of SHA256(key(event)). Returns 0u in
+  // case of an error.
+  //
+  // This ID is intended as the only ID for a particular structured metrics
+  // event. However, events are uploaded from the device alongside the UMA
+  // client ID, which is only removed after the event reaches the server. This
+  // means events are associated with the client ID when uploaded from the
+  // device. See the class comment of StructuredMetricsProvider for more
+  // details.
+  uint64_t UserEventId(uint64_t event);
+
+ private:
+  int GetRotationPeriod(uint64_t event);
+  void SetRotationPeriod(uint64_t event, int rotation_period);
+
+  int GetLastRotation(uint64_t event);
+  void SetLastRotation(uint64_t event, int last_rotation);
+
+  // Ensure that a valid key exists for |event|, and return it. Either returns a
+  // string of size |kKeySize| or base::nullopt, which indicates an error.
+  base::Optional<std::string> ValidateAndGetKey(uint64_t event);
+  void SetKey(uint64_t event, const std::string& key);
+
+  // Ensure that valid keys exist for all events.
+  void ValidateKeys();
+
+  // Storage for keys and rotation data. Must outlive the KeyData instance.
+  JsonPrefStore* key_store_;
+};
+
+}  // namespace internal
+}  // namespace structured
+}  // namespace metrics
+
+#endif  // COMPONENTS_METRICS_STRUCTURED_KEY_DATA_H_
diff --git a/components/metrics/structured/key_data_unittest.cc b/components/metrics/structured/key_data_unittest.cc
new file mode 100644
index 0000000..0581cd5
--- /dev/null
+++ b/components/metrics/structured/key_data_unittest.cc
@@ -0,0 +1,303 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/metrics/structured/key_data.h"
+
+#include <memory>
+#include <string>
+
+#include "base/containers/flat_set.h"
+#include "base/files/file_path.h"
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/test/scoped_mock_clock_override.h"
+#include "base/test/task_environment.h"
+#include "base/values.h"
+#include "components/metrics/structured/event_base.h"
+#include "components/metrics/structured/recorder.h"
+#include "components/prefs/json_pref_store.h"
+#include "components/prefs/persistent_pref_store.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace metrics {
+namespace structured {
+namespace internal {
+
+namespace {
+
+// 32 byte long test key, matching the size of a real key.
+constexpr char kKey[] = "abcdefghijklmnopqrstuvwxyzabcdef";
+
+// These event and metric names are used for testing.
+// - event: TestEventOne
+//   - metric: TestValueOne
+//   - metric: TestValueTwo
+// - event: TestEventTwo
+//   - metric: TestValueOne
+
+// The name hash of "TestEventOne".
+constexpr uint64_t kEventOneHash = UINT64_C(15619026293081468407);
+// The name hash of "TestEventTwo".
+constexpr uint64_t kEventTwoHash = UINT64_C(15791833939776536363);
+
+// The name hash of "TestMetricOne".
+constexpr uint64_t kMetricOneHash = UINT64_C(637929385654885975);
+// The name hash of "TestMetricTwo".
+constexpr uint64_t kMetricTwoHash = UINT64_C(14083999144141567134);
+
+// The hex-encoded frst 8 bytes of SHA256(kKey), ie. the user ID for key kKey.
+constexpr char kUserId[] = "2070DF23E0D95759";
+
+// Test values and their hashes. Hashes are the first 8 bytes of:
+//
+// HMAC_SHA256(concat(hex(kMetricNHash), kValueN),
+// "abcdefghijklmnopqrstuvwxyzabcdef")
+constexpr char kValueOne[] = "value one";
+constexpr char kValueTwo[] = "value two";
+constexpr char kValueOneHash[] = "805B8790DC69B773";
+constexpr char kValueTwoHash[] = "87CEF12FB15E0B3A";
+
+std::string HashToHex(const uint64_t hash) {
+  return base::HexEncode(&hash, sizeof(uint64_t));
+}
+
+std::string KeyPath(const uint64_t event) {
+  return base::StrCat({"keys.", base::NumberToString(event), ".key"});
+}
+
+std::string LastRotationPath(const uint64_t event) {
+  return base::StrCat({"keys.", base::NumberToString(event), ".last_rotation"});
+}
+
+std::string RotationPeriodPath(const uint64_t event) {
+  return base::StrCat(
+      {"keys.", base::NumberToString(event), ".rotation_period"});
+}
+
+}  // namespace
+
+class KeyDataTest : public testing::Test {
+ protected:
+  void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); }
+
+  void StandardSetup() {
+    MakeKeyStore();
+    MakeKeyData();
+    CommitKeyStore();
+  }
+
+  void ResetState() {
+    key_data_.reset();
+    key_store_.reset();
+    base::DeleteFile(GetKeyStorePath(), false);
+    ASSERT_FALSE(base::PathExists(GetKeyStorePath()));
+  }
+
+  void MakeKeyStore() {
+    key_store_ = new JsonPrefStore(GetKeyStorePath());
+    key_store_->ReadPrefs();
+  }
+
+  void MakeKeyData() { key_data_ = std::make_unique<KeyData>(GetKeyStore()); }
+
+  void CommitKeyStore() {
+    key_store_->CommitPendingWrite();
+    Wait();
+    ASSERT_TRUE(base::PathExists(GetKeyStorePath()));
+  }
+
+  JsonPrefStore* GetKeyStore() { return key_store_.get(); }
+
+  base::FilePath GetKeyStorePath() {
+    return temp_dir_.GetPath().Append("keys.json");
+  }
+
+  std::string GetString(const std::string& path) {
+    const base::Value* value;
+    GetKeyStore()->GetValue(path, &value);
+    return value->GetString();
+  }
+
+  int GetInt(const std::string& path) {
+    const base::Value* value;
+    GetKeyStore()->GetValue(path, &value);
+    return value->GetInt();
+  }
+
+  void SetString(const std::string& path, const std::string& value) {
+    key_store_->SetValue(path, std::make_unique<base::Value>(value),
+                         WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+    CommitKeyStore();
+  }
+
+  void SetInt(const std::string& path, const int value) {
+    key_store_->SetValue(path, std::make_unique<base::Value>(value),
+                         WriteablePrefStore::DEFAULT_PREF_WRITE_FLAGS);
+    CommitKeyStore();
+  }
+
+  void SetKeyData(const uint64_t event,
+                  const std::string& key,
+                  const int last_rotation,
+                  const int rotation_period) {
+    SetString(KeyPath(event), key);
+    SetInt(LastRotationPath(event), last_rotation);
+    SetInt(RotationPeriodPath(event), rotation_period);
+  }
+
+  void Wait() { task_environment_.RunUntilIdle(); }
+
+  base::test::TaskEnvironment task_environment_{
+      base::test::TaskEnvironment::MainThreadType::UI,
+      base::test::TaskEnvironment::ThreadPoolExecutionMode::QUEUED};
+  base::ScopedTempDir temp_dir_;
+  base::ScopedMockClockOverride time_;
+  scoped_refptr<JsonPrefStore> key_store_;
+
+  std::unique_ptr<KeyData> key_data_;
+};
+
+// If there is no key store file present, check that new keys are generated for
+// each event, and those keys are of the right length and different from each
+// other.
+TEST_F(KeyDataTest, GeneratesKeysForEvents) {
+  StandardSetup();
+  const std::string key_one = GetString(KeyPath(kEventOneHash));
+  const std::string key_two = GetString(KeyPath(kEventTwoHash));
+
+  EXPECT_EQ(key_one.size(), 32ul);
+  EXPECT_EQ(key_two.size(), 32ul);
+  EXPECT_NE(key_one, key_two);
+}
+
+// When repeatedly initialized with no key store file present, ensure the keys
+// generated each time are distinct.
+TEST_F(KeyDataTest, GeneratesDistinctKeys) {
+  base::flat_set<std::string> keys;
+
+  for (int i = 0; i < 10; ++i) {
+    ResetState();
+    StandardSetup();
+    keys.insert(GetString(KeyPath(kEventOneHash)));
+  }
+
+  EXPECT_EQ(keys.size(), 10ul);
+}
+
+// If there is an existing key store file, check that its keys are not replaced.
+TEST_F(KeyDataTest, ReuseExistingKeys) {
+  StandardSetup();
+  const std::string key_one = GetString(KeyPath(kEventOneHash));
+  CommitKeyStore();
+
+  key_data_.reset();
+  key_store_.reset();
+  StandardSetup();
+  const std::string key_two = GetString(KeyPath(kEventOneHash));
+
+  EXPECT_EQ(key_one, key_two);
+}
+
+// Check that different events have different hashes for the same metric and
+// value.
+TEST_F(KeyDataTest, DifferentEventsDifferentHashes) {
+  StandardSetup();
+  // Even though
+  EXPECT_NE(
+      key_data_->HashForEventMetric(kEventOneHash, kMetricOneHash, "value"),
+      key_data_->HashForEventMetric(kEventTwoHash, kMetricOneHash, "value"));
+}
+
+// Check that an event has different hashes for different values of the same
+// metric.
+TEST_F(KeyDataTest, DifferentMetricsDifferentHashes) {
+  StandardSetup();
+  EXPECT_NE(
+      key_data_->HashForEventMetric(kEventOneHash, kMetricOneHash, "first"),
+      key_data_->HashForEventMetric(kEventOneHash, kMetricOneHash, "second"));
+}
+
+// Check that an event has different hashes for different metrics with the same
+// value.
+TEST_F(KeyDataTest, DifferentValuesDifferentHashes) {
+  StandardSetup();
+  EXPECT_NE(
+      key_data_->HashForEventMetric(kEventOneHash, kMetricOneHash, "value"),
+      key_data_->HashForEventMetric(kEventOneHash, kMetricTwoHash, "value"));
+}
+
+// Ensure that KeyData::UserId is the expected value of SHA256(key).
+TEST_F(KeyDataTest, CheckUserIDs) {
+  MakeKeyStore();
+  SetKeyData(kEventOneHash, kKey, 0, 90);
+  CommitKeyStore();
+
+  MakeKeyData();
+  EXPECT_EQ(HashToHex(key_data_->UserEventId(kEventOneHash)), kUserId);
+  EXPECT_NE(HashToHex(key_data_->UserEventId(kEventTwoHash)), kUserId);
+}
+
+// Ensure that KeyData::Hash returns expected values for a known key and value.
+TEST_F(KeyDataTest, CheckHashes) {
+  MakeKeyStore();
+  SetString(KeyPath(kEventOneHash), kKey);
+  SetKeyData(kEventOneHash, kKey, 0, 90);
+  CommitKeyStore();
+
+  MakeKeyData();
+  EXPECT_EQ(HashToHex(key_data_->HashForEventMetric(kEventOneHash,
+                                                    kMetricOneHash, kValueOne)),
+            kValueOneHash);
+  EXPECT_EQ(HashToHex(key_data_->HashForEventMetric(kEventOneHash,
+                                                    kMetricTwoHash, kValueTwo)),
+            kValueTwoHash);
+}
+
+// Check that keys for a event are correctly rotated after the default 90 day
+// rotation period.
+TEST_F(KeyDataTest, KeysRotated) {
+  StandardSetup();
+  const uint64_t first_id = key_data_->UserEventId(kEventOneHash);
+  const int start_day = (base::Time::Now() - base::Time::UnixEpoch()).InDays();
+
+  // TestEventOne has a default rotation period of 90 days.
+  EXPECT_EQ(GetInt(RotationPeriodPath(kEventOneHash)), 90);
+
+  // Set the last rotation to today for testing.
+  SetInt(LastRotationPath(kEventOneHash), start_day);
+
+  {
+    // Advancing by 50 days, the key should not be rotated.
+    key_data_.reset();
+    time_.Advance(base::TimeDelta::FromDays(50));
+    StandardSetup();
+    EXPECT_EQ(key_data_->UserEventId(kEventOneHash), first_id);
+    EXPECT_EQ(GetInt(LastRotationPath(kEventOneHash)), start_day);
+  }
+
+  {
+    // Advancing by another 50 days, the key should be rotated and the last
+    // rotation day should be incremented by 90.
+    key_data_.reset();
+    time_.Advance(base::TimeDelta::FromDays(50));
+    StandardSetup();
+    EXPECT_NE(key_data_->UserEventId(kEventOneHash), first_id);
+    EXPECT_EQ(GetInt(LastRotationPath(kEventOneHash)), start_day + 90);
+  }
+
+  {
+    // Advancing by 453 days, the last rotation day should now 6 periods of 90
+    // days ahead.
+    key_data_.reset();
+    time_.Advance(base::TimeDelta::FromDays(453));
+    StandardSetup();
+    EXPECT_EQ(GetInt(LastRotationPath(kEventOneHash)), start_day + 6 * 90);
+  }
+}
+
+}  // namespace internal
+}  // namespace structured
+}  // namespace metrics
diff --git a/components/metrics/structured/structured_metrics_provider.h b/components/metrics/structured/structured_metrics_provider.h
index ec57468d..65ff1d8 100644
--- a/components/metrics/structured/structured_metrics_provider.h
+++ b/components/metrics/structured/structured_metrics_provider.h
@@ -28,6 +28,13 @@
 // thread safe and should only be called on the browser UI sequence, because
 // calls from the metrics service come on the UI sequence.
 //
+// Each structured metrics event is sent with other UMA data, and so is
+// associated with the UMA client ID when received by the UMA server. The client
+// ID is stripped from the events after they reach the server, and so data at
+// rest is not attached to the client ID. However, please note that structured
+// events are *not* separated from the client ID at the point of upload from
+// the device.
+//
 // Currently, the structured metrics system is cros-only and relies on the cros
 // cryptohome to store keys and unsent logs, collectively called 'state'. This
 // means structured metrics collection cannot begin until a profile eligible
diff --git a/components/omnibox/browser/scored_history_match_unittest.cc b/components/omnibox/browser/scored_history_match_unittest.cc
index 4b92625..203979fe 100644
--- a/components/omnibox/browser/scored_history_match_unittest.cc
+++ b/components/omnibox/browser/scored_history_match_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <algorithm>
 #include <memory>
+#include <numeric>
 #include <utility>
 
 #include "base/auto_reset.h"
@@ -13,7 +14,9 @@
 #include "base/i18n/break_iterator.h"
 #include "base/strings/string16.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "components/omnibox/browser/omnibox_field_trial.h"
+#include "components/omnibox/common/omnibox_features.h"
 #include "components/search_engines/search_terms_data.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -63,11 +66,12 @@
 
   // Convenience function for GetTopicalityScore() that builds the term match
   // and word break information automatically that are needed to call
-  // GetTopicalityScore().  It only works for scoring a single term, not
-  // multiple terms.
-  float GetTopicalityScoreOfTermAgainstURLAndTitle(const base::string16& term,
-                                                   const GURL& url,
-                                                   const base::string16& title);
+  // GetTopicalityScore().
+  float GetTopicalityScoreOfTermAgainstURLAndTitle(
+      const std::vector<const std::string>&,
+      const WordStarts term_word_starts,
+      const GURL& url,
+      const base::string16& title);
 };
 
 history::URLRow ScoredHistoryMatchTest::MakeURLRow(const char* url,
@@ -106,29 +110,29 @@
 }
 
 float ScoredHistoryMatchTest::GetTopicalityScoreOfTermAgainstURLAndTitle(
-    const base::string16& term,
+    const std::vector<const std::string>& terms,
+    const WordStarts term_word_starts,
     const GURL& url,
     const base::string16& title) {
-  String16Vector term_vector = {term};
-  WordStarts term_word_starts = {0};
-  base::i18n::BreakIterator iter(term, base::i18n::BreakIterator::BREAK_WORD);
-  if (iter.Init()) {
-    // Find the first word start.
-    while (iter.Advance() && !iter.IsWord()) {
-    }
-    term_word_starts[0] = iter.prev();
-  }
+  String16Vector term_vector;
+  std::transform(terms.begin(), terms.end(), std::back_inserter(term_vector),
+                 [](auto term) { return base::UTF8ToUTF16(term); });
+  std::string terms_joint =
+      std::accumulate(std::next(terms.begin()), terms.end(), terms[0],
+                      [](std::string accumulator, std::string term) {
+                        return accumulator + " " + term;
+                      });
   RowWordStarts row_word_starts;
   base::string16 url_string = base::UTF8ToUTF16(url.spec());
   String16SetFromString16(url_string, &row_word_starts.url_word_starts_);
   String16SetFromString16(title, &row_word_starts.title_word_starts_);
-  ScoredHistoryMatch scored_match(history::URLRow(GURL(url)), VisitInfoVector(),
-                                  term, term_vector, term_word_starts,
-                                  row_word_starts, false, 1, base::Time::Max());
-  scored_match.url_matches = MatchTermInString(term, url_string, 0);
-  scored_match.title_matches = MatchTermInString(term, title, 0);
+  auto row = history::URLRow(GURL(url));
+  row.set_title(title);
+  ScoredHistoryMatch scored_match(
+      row, VisitInfoVector(), base::UTF8ToUTF16(terms_joint), term_vector,
+      term_word_starts, row_word_starts, false, 1, base::Time::Max());
   scored_match.topicality_threshold_ = -1;
-  return scored_match.GetTopicalityScore(1, url,
+  return scored_match.GetTopicalityScore(term_vector.size(), url,
                                          base::OffsetAdjuster::Adjustments(),
                                          term_word_starts, row_word_starts);
 }
@@ -410,10 +414,10 @@
 
 TEST_F(ScoredHistoryMatchTest, GetTopicalityScoreTrailingSlash) {
   const float hostname = GetTopicalityScoreOfTermAgainstURLAndTitle(
-      ASCIIToUTF16("def"), GURL("http://abc.def.com/"),
+      {"def"}, {0}, GURL("http://abc.def.com/"),
       ASCIIToUTF16("Non-Matching Title"));
   const float hostname_no_slash = GetTopicalityScoreOfTermAgainstURLAndTitle(
-      ASCIIToUTF16("def"), GURL("http://abc.def.com"),
+      {"def"}, {0}, GURL("http://abc.def.com"),
       ASCIIToUTF16("Non-Matching Title"));
   EXPECT_EQ(hostname_no_slash, hostname);
 }
@@ -524,14 +528,36 @@
   // is a valid match at a word break.  To recognize this,
   // |terms_to_word_starts_offsets| must record that the "word" in this term
   // starts at the second character.
-  terms_to_word_starts_offsets[0] = 1;
   term_matches.clear();
   term_matches.push_back(TermMatch(0, 27, 1));
   filtered_term_matches = ScoredHistoryMatch::FilterTermMatchesByWordStarts(
-      term_matches, terms_to_word_starts_offsets, word_starts, 15,
+      term_matches, /*terms_to_word_starts_offsets*/ {1}, word_starts, 15,
       std::string::npos);
   ASSERT_EQ(1u, filtered_term_matches.size());
   EXPECT_EQ(27u, filtered_term_matches[0].offset);
+
+  // Check "de" + "fa" + "lt" matches "defa" when |allow_midword_continuations|
+  // is true.
+  term_matches.clear();
+  term_matches.push_back(TermMatch(0, 16, 2));
+  term_matches.push_back(TermMatch(1, 18, 2));
+  term_matches.push_back(TermMatch(2, 21, 2));
+  filtered_term_matches = ScoredHistoryMatch::FilterTermMatchesByWordStarts(
+      term_matches, {0, 0, 0}, word_starts, 15, std::string::npos, true);
+  ASSERT_EQ(2u, filtered_term_matches.size());
+  EXPECT_EQ(16u, filtered_term_matches[0].offset);
+  EXPECT_EQ(18u, filtered_term_matches[1].offset);
+
+  // Check "de" + "fa" + "lt" matches "de" when |allow_midword_continuations| is
+  // false.
+  term_matches.clear();
+  term_matches.push_back(TermMatch(0, 16, 2));
+  term_matches.push_back(TermMatch(1, 18, 2));
+  term_matches.push_back(TermMatch(2, 21, 2));
+  filtered_term_matches = ScoredHistoryMatch::FilterTermMatchesByWordStarts(
+      term_matches, {0, 0, 0}, word_starts, 15, std::string::npos, false);
+  ASSERT_EQ(1u, filtered_term_matches.size());
+  EXPECT_EQ(16u, filtered_term_matches[0].offset);
 }
 
 TEST_F(ScoredHistoryMatchTest, GetFrequency) {
@@ -629,30 +655,31 @@
 TEST_F(ScoredHistoryMatchTest, GetTopicalityScore) {
   GURL url("http://abc.def.com/path1/path2?arg1=val1&arg2=val2#hash_fragment");
   base::string16 title = ASCIIToUTF16("here is a - title");
-  auto Score = [&](const char* term) {
-    return GetTopicalityScoreOfTermAgainstURLAndTitle(ASCIIToUTF16(term), url,
-                                                      title);
+  auto Score = [&](const std::vector<const std::string>& term_vector,
+                   const WordStarts term_word_starts) {
+    return GetTopicalityScoreOfTermAgainstURLAndTitle(
+        term_vector, term_word_starts, url, title);
   };
-  const float hostname_score = Score("abc");
-  const float hostname_mid_word_score = Score("bc");
-  const float hostname_score_preceeding_punctuation = Score("://abc");
-  const float domain_name_score = Score("def");
-  const float domain_name_mid_word_score = Score("ef");
-  const float domain_name_score_preceeding_dot = Score(".def");
-  const float tld_score = Score("com");
-  const float tld_mid_word_score = Score("om");
-  const float tld_score_preceeding_dot = Score(".com");
-  const float path_score = Score("path1");
-  const float path_mid_word_score = Score("ath1");
-  const float path_score_preceeding_slash = Score("/path1");
-  const float arg_score = Score("arg1");
-  const float arg_mid_word_score = Score("rg1");
-  const float arg_score_preceeding_question_mark = Score("?arg1");
-  const float protocol_score = Score("htt");
-  const float protocol_mid_word_score = Score("tt");
-  const float title_score = Score("her");
-  const float title_mid_word_score = Score("er");
-  const float wordless_match_at_title_mid_word_score = Score("-");
+  const float hostname_score = Score({"abc"}, {0});
+  const float hostname_mid_word_score = Score({"bc"}, {0});
+  const float hostname_score_preceeding_punctuation = Score({"://abc"}, {3});
+  const float domain_name_score = Score({"def"}, {0});
+  const float domain_name_mid_word_score = Score({"ef"}, {0});
+  const float domain_name_score_preceeding_dot = Score({".def"}, {1});
+  const float tld_score = Score({"com"}, {0});
+  const float tld_mid_word_score = Score({"om"}, {0});
+  const float tld_score_preceeding_dot = Score({".com"}, {1});
+  const float path_score = Score({"path1"}, {0});
+  const float path_mid_word_score = Score({"ath1"}, {0});
+  const float path_score_preceeding_slash = Score({"/path1"}, {1});
+  const float arg_score = Score({"arg1"}, {0});
+  const float arg_mid_word_score = Score({"rg1"}, {0});
+  const float arg_score_preceeding_question_mark = Score({"?arg1"}, {1});
+  const float protocol_score = Score({"htt"}, {0});
+  const float protocol_mid_word_score = Score({"tt"}, {0});
+  const float title_score = Score({"her"}, {0});
+  const float title_mid_word_score = Score({"er"}, {0});
+  const float wordless_match_at_title_mid_word_score = Score({"-"}, {1});
   // Verify hostname and domain name > path > arg.
   EXPECT_GT(hostname_score, path_score);
   EXPECT_GT(domain_name_score, path_score);
@@ -684,7 +711,6 @@
   EXPECT_EQ(protocol_mid_word_score, 0);
   EXPECT_EQ(title_mid_word_score, 0);
   EXPECT_GT(wordless_match_at_title_mid_word_score, 0);
-  // Verify matches not at word starts score non 0 when they contain no words.
   // Check that title matches fit somewhere reasonable compared to the
   // various types of URL matches.
   EXPECT_GT(title_score, arg_score);
@@ -696,6 +722,46 @@
   EXPECT_GT(hostname_mid_word_score, protocol_mid_word_score);
   EXPECT_GT(hostname_mid_word_score, tld_score);
   EXPECT_GT(hostname_mid_word_score, tld_mid_word_score);
+
+  // Check that midword matches are not allowed when
+  // kHistoryQuickProviderAllowButDoNotScoreMidwordTerms is disabled.
+  {
+    base::test::ScopedFeatureList feature_list;
+    feature_list.InitAndDisableFeature(
+        omnibox::kHistoryQuickProviderAllowButDoNotScoreMidwordTerms);
+
+    const float wordstart = Score({"frag"}, {0u});
+    const float midword = Score({"ment"}, {0u});
+    const float wordstart_midword_continuation =
+        Score({"frag", "ment"}, {0u, 0u});
+    const float wordstart_midword_disjoint = Score({"frag", "ent"}, {0u, 0u});
+
+    EXPECT_GT(wordstart, 0);
+    EXPECT_EQ(midword, 0);
+    EXPECT_EQ(wordstart_midword_continuation, 0);
+    EXPECT_EQ(wordstart_midword_disjoint, 0);
+  }
+
+  // Check that midword matches are allowed but not scored when
+  // kHistoryQuickProviderAllowButDoNotScoreMidwordTerms is enabled.
+  {
+    base::test::ScopedFeatureList feature_list;
+    feature_list.InitAndEnableFeature(
+        omnibox::kHistoryQuickProviderAllowButDoNotScoreMidwordTerms);
+
+    const float wordstart = Score({"frag"}, {0u});
+    const float midword = Score({"ment"}, {0u});
+    const float wordstart_midword_continuation =
+        Score({"frag", "ment"}, {0u, 0u});
+    const float wordstart_midword_disjoint = Score({"frag", "ent"}, {0u, 0u});
+
+    EXPECT_GT(wordstart, 0);
+    EXPECT_EQ(midword, 0);
+    EXPECT_GT(wordstart_midword_continuation, 0);
+    EXPECT_GT(wordstart_midword_disjoint, 0);
+    EXPECT_GT(wordstart, wordstart_midword_continuation);
+    EXPECT_EQ(wordstart_midword_continuation, wordstart_midword_disjoint);
+  }
 }
 
 // Test the function GetFinalRelevancyScore().
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc
index 78a55e14..72329942 100644
--- a/components/omnibox/common/omnibox_features.cc
+++ b/components/omnibox/common/omnibox_features.cc
@@ -294,19 +294,19 @@
 const base::Feature kOmniboxExperimentalSuggestScoring{
     "OmniboxExperimentalSuggestScoring", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// If disabled, terms with no wordstart matches disqualify the suggestion. If
-// enabled, terms with no wordstart matches are allowed but not scored. E.g.,
-// both inputs 'java script' and 'java cript' will match a suggestion titled
-// 'javascript' and score equivalently.
+// If disabled, terms with no wordstart matches disqualify the suggestion unless
+// they occur in the URL host. If enabled, terms with no wordstart matches are
+// allowed but not scored. E.g., both inputs 'java script' and 'java cript' will
+// match a suggestion titled 'javascript' and score equivalently.
 const base::Feature kHistoryQuickProviderAllowButDoNotScoreMidwordTerms{
     "OmniboxHistoryQuickProviderAllowButDoNotScoreMidwordTerms",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
-// If disabled, midword matches are ignored and input terms with no wordstart
-// matches are scored 0, resulting in an overall score of 0. If enabled, midword
-// matches are allowed and scored when they begin immediately after the previous
-// match ends. E.g. 'java script' will match a suggestion titled 'javascript'
-// but the input 'java cript' won't.
+// If disabled, midword matches are ignored except in the URL host, and input
+// terms with no wordstart matches are scored 0, resulting in an overall score
+// of 0. If enabled, midword matches are allowed and scored when they begin
+// immediately after the previous match ends. E.g. 'java script' will match a
+// suggestion titled 'javascript' but the input 'java cript' won't.
 const base::Feature kHistoryQuickProviderAllowMidwordContinuations{
     "OmniboxHistoryQuickProviderAllowMidwordContinuations",
     base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/optimization_guide/hints_fetcher.cc b/components/optimization_guide/hints_fetcher.cc
index c2e52ee..bb29f82f7 100644
--- a/components/optimization_guide/hints_fetcher.cc
+++ b/components/optimization_guide/hints_fetcher.cc
@@ -67,6 +67,14 @@
   return valid_urls;
 }
 
+void RecordRequestStatusHistogram(proto::RequestContext request_context,
+                                  HintsFetcherRequestStatus status) {
+  base::UmaHistogramEnumeration(
+      "OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus." +
+          GetStringNameForRequestContext(request_context),
+      status);
+}
+
 }  // namespace
 
 HintsFetcher::HintsFetcher(
@@ -131,16 +139,16 @@
   DCHECK_GT(optimization_types.size(), 0u);
 
   if (content::GetNetworkConnectionTracker()->IsOffline()) {
-    std::move(hints_fetched_callback)
-        .Run(request_context, HintsFetcherRequestStatus::kNetworkOffline,
-             base::nullopt);
+    RecordRequestStatusHistogram(request_context,
+                                 HintsFetcherRequestStatus::kNetworkOffline);
+    std::move(hints_fetched_callback).Run(base::nullopt);
     return false;
   }
 
   if (active_url_loader_) {
-    std::move(hints_fetched_callback)
-        .Run(request_context, HintsFetcherRequestStatus::kFetcherBusy,
-             base::nullopt);
+    RecordRequestStatusHistogram(request_context,
+                                 HintsFetcherRequestStatus::kFetcherBusy);
+    std::move(hints_fetched_callback).Run(base::nullopt);
     return false;
   }
 
@@ -148,9 +156,9 @@
       GetSizeLimitedHostsDueForHintsRefresh(hosts);
   std::vector<GURL> valid_urls = GetValidURLsForFetching(urls);
   if (filtered_hosts.empty() && valid_urls.empty()) {
-    std::move(hints_fetched_callback)
-        .Run(request_context, HintsFetcherRequestStatus::kNoHostsOrURLsToFetch,
-             base::nullopt);
+    RecordRequestStatusHistogram(
+        request_context, HintsFetcherRequestStatus::kNoHostsOrURLsToFetch);
+    std::move(hints_fetched_callback).Run(base::nullopt);
     return false;
   }
 
@@ -158,33 +166,33 @@
             filtered_hosts.size());
 
   if (optimization_types.empty()) {
-    std::move(hints_fetched_callback)
-        .Run(request_context,
-             HintsFetcherRequestStatus::kNoSupportedOptimizationTypes,
-             base::nullopt);
+    RecordRequestStatusHistogram(
+        request_context,
+        HintsFetcherRequestStatus::kNoSupportedOptimizationTypes);
+    std::move(hints_fetched_callback).Run(base::nullopt);
     return false;
   }
 
   hints_fetch_start_time_ = base::TimeTicks::Now();
   request_context_ = request_context;
 
-  get_hints_request_ = std::make_unique<proto::GetHintsRequest>();
+  proto::GetHintsRequest get_hints_request;
 
   for (const auto& optimization_type : optimization_types)
-    get_hints_request_->add_supported_optimizations(optimization_type);
+    get_hints_request.add_supported_optimizations(optimization_type);
 
-  get_hints_request_->set_context(request_context_);
+  get_hints_request.set_context(request_context_);
 
   for (const auto& url : valid_urls)
-    get_hints_request_->add_urls()->set_url(url.spec());
+    get_hints_request.add_urls()->set_url(url.spec());
 
   for (const auto& host : filtered_hosts) {
-    proto::HostInfo* host_info = get_hints_request_->add_hosts();
+    proto::HostInfo* host_info = get_hints_request.add_hosts();
     host_info->set_host(host);
   }
 
   std::string serialized_request;
-  get_hints_request_->SerializeToString(&serialized_request);
+  get_hints_request.SerializeToString(&serialized_request);
 
   net::NetworkTrafficAnnotationTag traffic_annotation =
       net::DefineNetworkTrafficAnnotation("hintsfetcher_gethintsrequest", R"(
@@ -274,13 +282,13 @@
             GetStringNameForRequestContext(request_context_),
         fetch_latency);
     UpdateHostsSuccessfullyFetched();
-    std::move(hints_fetched_callback_)
-        .Run(request_context_, HintsFetcherRequestStatus::kSuccess,
-             std::move(get_hints_response));
+    RecordRequestStatusHistogram(request_context_,
+                                 HintsFetcherRequestStatus::kSuccess);
+    std::move(hints_fetched_callback_).Run(std::move(get_hints_response));
   } else {
-    std::move(hints_fetched_callback_)
-        .Run(request_context_, HintsFetcherRequestStatus::kResponseError,
-             base::nullopt);
+    RecordRequestStatusHistogram(request_context_,
+                                 HintsFetcherRequestStatus::kResponseError);
+    std::move(hints_fetched_callback_).Run(base::nullopt);
   }
 }
 
diff --git a/components/optimization_guide/hints_fetcher.h b/components/optimization_guide/hints_fetcher.h
index 7bb8829..31118b4 100644
--- a/components/optimization_guide/hints_fetcher.h
+++ b/components/optimization_guide/hints_fetcher.h
@@ -58,8 +58,6 @@
 // to pass back the fetched hints response from the remote Optimization Guide
 // Service.
 using HintsFetchedCallback = base::OnceCallback<void(
-    optimization_guide::proto::RequestContext request_context,
-    HintsFetcherRequestStatus fetch_status,
     base::Optional<std::unique_ptr<proto::GetHintsResponse>>)>;
 
 // A class to handle requests for optimization hints from a remote Optimization
@@ -135,10 +133,6 @@
   std::vector<std::string> GetSizeLimitedHostsDueForHintsRefresh(
       const std::vector<std::string>& hosts) const;
 
-  // Used to hold the GetHintsRequest being constructed and sent as a remote
-  // request.
-  std::unique_ptr<proto::GetHintsRequest> get_hints_request_;
-
   // Used to hold the callback while the SimpleURLLoader performs the request
   // asynchronously.
   HintsFetchedCallback hints_fetched_callback_;
diff --git a/components/optimization_guide/hints_fetcher_unittest.cc b/components/optimization_guide/hints_fetcher_unittest.cc
index e554707..04be60d 100644
--- a/components/optimization_guide/hints_fetcher_unittest.cc
+++ b/components/optimization_guide/hints_fetcher_unittest.cc
@@ -55,21 +55,14 @@
     hints_fetcher_->SetTimeClockForTesting(task_environment_.GetMockClock());
   }
 
-  ~HintsFetcherTest() override {}
+  ~HintsFetcherTest() override = default;
 
-  void OnHintsFetched(
-      optimization_guide::proto::RequestContext request_context,
-      optimization_guide::HintsFetcherRequestStatus fetcher_request_status,
-      base::Optional<std::unique_ptr<proto::GetHintsResponse>>
-          get_hints_response) {
-    fetcher_request_status_ = fetcher_request_status;
+  void OnHintsFetched(base::Optional<std::unique_ptr<proto::GetHintsResponse>>
+                          get_hints_response) {
     if (get_hints_response)
       hints_fetched_ = true;
   }
 
-  optimization_guide::HintsFetcherRequestStatus fetcher_request_status() {
-    return fetcher_request_status_;
-  }
   bool hints_fetched() { return hints_fetched_; }
 
   void SetConnectionOffline() {
@@ -150,8 +143,6 @@
     base::RunLoop().RunUntilIdle();
   }
 
-  optimization_guide::HintsFetcherRequestStatus fetcher_request_status_ =
-      optimization_guide::HintsFetcherRequestStatus::kUnknown;
   bool hints_fetched_ = false;
   base::test::TaskEnvironment task_environment_;
 
@@ -172,8 +163,6 @@
   EXPECT_TRUE(FetchHints({"foo.com"}, {} /* urls */));
   VerifyHasPendingFetchRequests();
   EXPECT_TRUE(SimulateResponse(response_content, net::HTTP_OK));
-  EXPECT_EQ(optimization_guide::HintsFetcherRequestStatus::kSuccess,
-            fetcher_request_status());
   EXPECT_TRUE(hints_fetched());
 
   histogram_tester.ExpectTotalCount(
@@ -181,6 +170,10 @@
   histogram_tester.ExpectTotalCount(
       "OptimizationGuide.HintsFetcher.GetHintsRequest.FetchLatency.BatchUpdate",
       1);
+  histogram_tester.ExpectUniqueSample(
+      "OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
+      "BatchUpdate",
+      HintsFetcherRequestStatus::kSuccess, 1);
 }
 
 // Tests to ensure that multiple hint fetches by the same object cannot be in
@@ -189,19 +182,29 @@
   base::SimpleTestClock test_clock;
   SetTimeClockForTesting(&test_clock);
 
-  std::string response_content;
   // Fetch back to back without waiting for Fetch to complete,
   // |fetch_in_progress_| should cause early exit.
-  EXPECT_TRUE(FetchHints({"foo.com"}, {} /* urls */));
-  EXPECT_FALSE(FetchHints({"bar.com"}, {} /* urls */));
-  EXPECT_EQ(optimization_guide::HintsFetcherRequestStatus::kFetcherBusy,
-            fetcher_request_status());
+  {
+    base::HistogramTester histogram_tester;
+    EXPECT_TRUE(FetchHints({"foo.com"}, {} /* urls */));
+    EXPECT_FALSE(FetchHints({"bar.com"}, {} /* urls */));
+    histogram_tester.ExpectUniqueSample(
+        "OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
+        "BatchUpdate",
+        HintsFetcherRequestStatus::kFetcherBusy, 1);
+  }
 
   // Once response arrives, check to make sure a new fetch can start.
-  SimulateResponse(response_content, net::HTTP_OK);
-  EXPECT_TRUE(FetchHints({"bar.com"}, {} /* urls */));
-  EXPECT_EQ(optimization_guide::HintsFetcherRequestStatus::kSuccess,
-            fetcher_request_status());
+  {
+    base::HistogramTester histogram_tester;
+    std::string response_content;
+    SimulateResponse(response_content, net::HTTP_OK);
+    EXPECT_TRUE(FetchHints({"bar.com"}, {} /* urls */));
+    histogram_tester.ExpectUniqueSample(
+        "OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
+        "BatchUpdate",
+        HintsFetcherRequestStatus::kSuccess, 1);
+  }
 }
 
 // Tests that the hints are refreshed again for hosts for whom hints were
@@ -269,12 +272,14 @@
   // Send a 404 to HintsFetcher.
   SimulateResponse(response_content, net::HTTP_NOT_FOUND);
   EXPECT_FALSE(hints_fetched());
-  EXPECT_EQ(optimization_guide::HintsFetcherRequestStatus::kResponseError,
-            fetcher_request_status());
 
-  // Make sure histogram not recorded on bad response.
+  // Make sure histograms are recorded correctly on bad response.
   histogram_tester.ExpectTotalCount(
       "OptimizationGuide.HintsFetcher.GetHintsRequest.FetchLatency", 0);
+  histogram_tester.ExpectUniqueSample(
+      "OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
+      "BatchUpdate",
+      HintsFetcherRequestStatus::kResponseError, 1);
 }
 
 TEST_F(HintsFetcherTest, FetchReturnBadResponse) {
@@ -285,12 +290,14 @@
   VerifyHasPendingFetchRequests();
   EXPECT_TRUE(SimulateResponse(response_content, net::HTTP_OK));
   EXPECT_FALSE(hints_fetched());
-  EXPECT_EQ(optimization_guide::HintsFetcherRequestStatus::kResponseError,
-            fetcher_request_status());
 
-  // Make sure histogram not recorded on bad response.
+  // Make sure histograms are recorded correctly on bad response.
   histogram_tester.ExpectTotalCount(
       "OptimizationGuide.HintsFetcher.GetHintsRequest.FetchLatency", 0);
+  histogram_tester.ExpectUniqueSample(
+      "OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
+      "BatchUpdate",
+      HintsFetcherRequestStatus::kResponseError, 1);
 }
 
 TEST_F(HintsFetcherTest, FetchAttemptWhenNetworkOffline) {
@@ -300,12 +307,14 @@
   std::string response_content;
   EXPECT_FALSE(FetchHints({"foo.com"}, {} /* urls */));
   EXPECT_FALSE(hints_fetched());
-  EXPECT_EQ(optimization_guide::HintsFetcherRequestStatus::kNetworkOffline,
-            fetcher_request_status());
 
-  // Make sure histogram not recorded on bad response.
+  // Make sure histograms are recorded correctly on bad response.
   histogram_tester.ExpectTotalCount(
       "OptimizationGuide.HintsFetcher.GetHintsRequest.FetchLatency", 0);
+  histogram_tester.ExpectUniqueSample(
+      "OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
+      "BatchUpdate",
+      HintsFetcherRequestStatus::kNetworkOffline, 1);
 
   SetConnectionOnline();
   EXPECT_TRUE(FetchHints({"foo.com"}, {} /* urls */));
@@ -385,7 +394,6 @@
 }
 
 TEST_F(HintsFetcherTest, HintsFetcherHostsCovered) {
-  base::HistogramTester histogram_tester;
   std::vector<std::string> hosts{"host1.com", "host2.com"};
   base::Time host_invalid_time =
       base::Time::Now() + base::TimeDelta().FromHours(1);
@@ -397,7 +405,6 @@
 }
 
 TEST_F(HintsFetcherTest, HintsFetcherCoveredHostExpired) {
-  base::HistogramTester histogram_tester;
   std::string response_content;
   std::vector<std::string> hosts{"host1.com", "host2.com"};
   base::Time host_invalid_time =
@@ -430,7 +437,6 @@
 }
 
 TEST_F(HintsFetcherTest, HintsFetcherHostNotCovered) {
-  base::HistogramTester histogram_tester;
   std::vector<std::string> hosts{"host1.com", "host2.com"};
   base::Time host_invalid_time =
       base::Time::Now() + base::TimeDelta().FromHours(1);
@@ -446,7 +452,6 @@
 }
 
 TEST_F(HintsFetcherTest, HintsFetcherRemoveExpiredOnSuccessfullyFetched) {
-  base::HistogramTester histogram_tester;
   std::string response_content;
   std::vector<std::string> hosts_expired{"host1.com", "host2.com"};
   base::Time host_invalid_time =
@@ -475,7 +480,6 @@
 }
 
 TEST_F(HintsFetcherTest, HintsFetcherSuccessfullyFetchedHostsFull) {
-  base::HistogramTester histogram_tester;
   std::string response_content;
   std::vector<std::string> hosts;
   size_t max_hosts =
@@ -505,7 +509,6 @@
 }
 
 TEST_F(HintsFetcherTest, MaxHostsForOptimizationGuideServiceHintsFetch) {
-  base::HistogramTester histogram_tester;
   std::string response_content;
   std::vector<std::string> all_hosts;
 
@@ -546,8 +549,6 @@
   EXPECT_TRUE(FetchHints({}, {GURL("https://baz.com/r/werd")}));
   VerifyHasPendingFetchRequests();
   EXPECT_TRUE(SimulateResponse(response_content, net::HTTP_OK));
-  EXPECT_EQ(optimization_guide::HintsFetcherRequestStatus::kSuccess,
-            fetcher_request_status());
   EXPECT_TRUE(hints_fetched());
 
   histogram_tester.ExpectTotalCount(
@@ -555,6 +556,10 @@
   histogram_tester.ExpectTotalCount(
       "OptimizationGuide.HintsFetcher.GetHintsRequest.FetchLatency.BatchUpdate",
       1);
+  histogram_tester.ExpectUniqueSample(
+      "OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
+      "BatchUpdate",
+      static_cast<int>(HintsFetcherRequestStatus::kSuccess), 1);
 }
 
 TEST_F(HintsFetcherTest, NoHostsOrURLsToFetch) {
@@ -564,9 +569,10 @@
   EXPECT_FALSE(FetchHints({} /* hosts */, {} /* urls */
                           ));
   EXPECT_FALSE(hints_fetched());
-  EXPECT_EQ(
-      optimization_guide::HintsFetcherRequestStatus::kNoHostsOrURLsToFetch,
-      fetcher_request_status());
+  histogram_tester.ExpectUniqueSample(
+      "OptimizationGuide.HintsFetcher.GetHintsRequest.RequestStatus."
+      "BatchUpdate",
+      static_cast<int>(HintsFetcherRequestStatus::kNoHostsOrURLsToFetch), 1);
 }
 
 }  // namespace optimization_guide
diff --git a/components/safe_browsing/core/features.cc b/components/safe_browsing/core/features.cc
index 6d922e8..64261588 100644
--- a/components/safe_browsing/core/features.cc
+++ b/components/safe_browsing/core/features.cc
@@ -50,12 +50,15 @@
 
 const base::Feature kPasswordProtectionShowDomainsForSavedPasswords{
     "SafeBrowsingPasswordProtectionShowDomainsForSavedPasswords",
-    base::FEATURE_ENABLED_BY_DEFAULT};
+    base::FEATURE_DISABLED_BY_DEFAULT};
 
 const base::Feature kPasswordProtectionForSignedInUsers{
     "SafeBrowsingPasswordProtectionForSignedInUsers",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
+const base::Feature kPromptAppForDeepScanning{
+    "SafeBrowsingPromptAppForDeepScanning", base::FEATURE_DISABLED_BY_DEFAULT};
+
 const base::Feature kRealTimeUrlLookupEnabled{
     "SafeBrowsingRealTimeUrlLookupEnabled", base::FEATURE_DISABLED_BY_DEFAULT};
 
@@ -85,7 +88,7 @@
 
 const base::Feature kSendSampledPingsForAllowlistDomains{
     "SafeBrowsingSendSampledPingsForAllowlistDomain",
-    base::FEATURE_DISABLED_BY_DEFAULT};
+    base::FEATURE_ENABLED_BY_DEFAULT};
 
 constexpr base::FeatureParam<bool> kShouldFillOldPhishGuardProto{
     &kPasswordProtectionForSignedInUsers, "DeprecateOldProto", false};
@@ -109,7 +112,7 @@
 namespace {
 // List of Safe Browsing features. Boolean value for each list member should be
 // set to true if the experiment state should be listed on
-// chrome://safe-browsing.
+// chrome://safe-browsing. Features should be listed in alphabetical order.
 constexpr struct {
   const base::Feature* feature;
   // True if the feature's state should be listed on chrome://safe-browsing.
@@ -126,6 +129,7 @@
     {&kPasswordProtectionForSavedPasswords, true},
     {&kPasswordProtectionShowDomainsForSavedPasswords, true},
     {&kPasswordProtectionForSignedInUsers, true},
+    {&kPromptAppForDeepScanning, true},
     {&kRealTimeUrlLookupEnabled, true},
     {&kSendOnFocusPing, true},
     {&kSendPasswordReusePing, true},
diff --git a/components/safe_browsing/core/features.h b/components/safe_browsing/core/features.h
index 57b43a7..d0a5e71 100644
--- a/components/safe_browsing/core/features.h
+++ b/components/safe_browsing/core/features.h
@@ -18,7 +18,8 @@
 }  // namespace base
 
 namespace safe_browsing {
-// Features list
+// Features list, in alphabetical order.
+
 // Controls whether we send RIND reports when a popup originating from a Google
 // Ad is blocked.
 extern const base::Feature kAdPopupTriggerFeature;
@@ -51,11 +52,6 @@
 // sent for scanning.
 extern const base::Feature kMalwareScanEnabled;
 
-// Controls whether the user has forcibly enabled AP download protection. This
-// flag will enable AP downloads protections even for users not enrolled in
-// APP.
-extern const base::Feature kForceUseAPDownloadProtection;
-
 // Enable password protection for non-Google accounts.
 extern const base::Feature kPasswordProtectionForSavedPasswords;
 
@@ -67,6 +63,9 @@
 // Enable GAIA password protection for signed-in users.
 extern const base::Feature kPasswordProtectionForSignedInUsers;
 
+// Controls whether Chrome prompts Advanced Protection users for deep scanning.
+extern const base::Feature kPromptAppForDeepScanning;
+
 // Controls whether Chrome sends on focus ping.
 extern const base::Feature kSendOnFocusPing;
 
diff --git a/components/viz/service/frame_sinks/video_detector_unittest.cc b/components/viz/service/frame_sinks/video_detector_unittest.cc
index 588f9c0..df4c9f5 100644
--- a/components/viz/service/frame_sinks/video_detector_unittest.cc
+++ b/components/viz/service/frame_sinks/video_detector_unittest.cc
@@ -84,7 +84,7 @@
                             false,
                             false) {}
 
-  ~VideoDetectorTest() override {}
+  ~VideoDetectorTest() override = default;
 
   void SetUp() override {
     mock_task_runner_ = base::MakeRefCounted<base::TestMockTimeTaskRunner>(
diff --git a/content/browser/background_sync/background_sync_scheduler.cc b/content/browser/background_sync/background_sync_scheduler.cc
index 56c324e..8e782e8e 100644
--- a/content/browser/background_sync/background_sync_scheduler.cc
+++ b/content/browser/background_sync/background_sync_scheduler.cc
@@ -85,7 +85,17 @@
   DCHECK(storage_partition);
 
   auto& delayed_processing_info = GetDelayedProcessingInfoMap(sync_type);
-  delayed_processing_info.erase(storage_partition);
+  if (delayed_processing_info.count(storage_partition)) {
+    base::TimeTicks run_time =
+        delayed_processing_info[storage_partition]->desired_run_time();
+
+    // If this storage partition was scheduling the next wakeup, reset the
+    // wakeup time for |sync_type|.
+    if (scheduled_wakeup_time_[sync_type] == run_time)
+      scheduled_wakeup_time_[sync_type] = base::TimeTicks::Max();
+
+    delayed_processing_info.erase(storage_partition);
+  }
 
 #if defined(OS_ANDROID)
   ScheduleOrCancelBrowserWakeupForSyncType(sync_type, storage_partition);
@@ -108,13 +118,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   std::move(delayed_task).Run();
-
-  auto& delayed_processing_info = GetDelayedProcessingInfoMap(sync_type);
-  delayed_processing_info.erase(storage_partition);
-
-#if defined(OS_ANDROID)
-  ScheduleOrCancelBrowserWakeupForSyncType(sync_type, storage_partition);
-#endif
+  CancelDelayedProcessing(storage_partition, sync_type);
 }
 
 #if defined(OS_ANDROID)
@@ -133,6 +137,7 @@
   // If no more scheduled tasks remain, cancel browser wakeup.
   // Canceling when there's no task scheduled is a no-op.
   if (delayed_processing_info.empty()) {
+    scheduled_wakeup_time_[sync_type] = base::TimeTicks::Max();
     controller->CancelBrowserWakeup(sync_type);
     return;
   }
@@ -144,6 +149,15 @@
         return (lhs.second->desired_run_time() - base::TimeTicks::Now()) <
                (rhs.second->desired_run_time() - base::TimeTicks::Now());
       });
+
+  base::TimeTicks next_time = min_info.second->desired_run_time();
+  if (next_time >= scheduled_wakeup_time_[sync_type]) {
+    // There's an earlier wakeup time scheduled, no need to inform the
+    // scheduler.
+    return;
+  }
+
+  scheduled_wakeup_time_[sync_type] = next_time;
   controller->ScheduleBrowserWakeUpWithDelay(
       sync_type, min_info.second->desired_run_time() - base::TimeTicks::Now());
 }
diff --git a/content/browser/background_sync/background_sync_scheduler.h b/content/browser/background_sync/background_sync_scheduler.h
index 7dc71fd..99a76b28 100644
--- a/content/browser/background_sync/background_sync_scheduler.h
+++ b/content/browser/background_sync/background_sync_scheduler.h
@@ -57,6 +57,7 @@
 
   friend struct BrowserThread::DeleteOnThread<BrowserThread::UI>;
   friend class base::DeleteHelper<BackgroundSyncScheduler>;
+  friend class BackgroundSyncSchedulerTest;
 
   std::map<StoragePartitionImpl*, std::unique_ptr<base::OneShotTimer>>&
   GetDelayedProcessingInfoMap(blink::mojom::BackgroundSyncType sync_type);
@@ -74,6 +75,12 @@
   std::map<StoragePartitionImpl*, std::unique_ptr<base::OneShotTimer>>
       delayed_processing_info_periodic_;
 
+  std::map<blink::mojom::BackgroundSyncType, base::TimeTicks>
+      scheduled_wakeup_time_{
+          {blink::mojom::BackgroundSyncType::ONE_SHOT, base::TimeTicks::Max()},
+          {blink::mojom::BackgroundSyncType::PERIODIC, base::TimeTicks::Max()},
+      };
+
   base::WeakPtrFactory<BackgroundSyncScheduler> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(BackgroundSyncScheduler);
diff --git a/content/browser/background_sync/background_sync_scheduler_unittest.cc b/content/browser/background_sync/background_sync_scheduler_unittest.cc
index 6fa5d95..9d9bcc3 100644
--- a/content/browser/background_sync/background_sync_scheduler_unittest.cc
+++ b/content/browser/background_sync/background_sync_scheduler_unittest.cc
@@ -93,6 +93,14 @@
     return GetController()->GetBrowserWakeupDelay(sync_type);
   }
 
+  base::TimeTicks GetBrowserWakeupTime() {
+    auto* scheduler = BackgroundSyncScheduler::GetFor(&test_browser_context_);
+    DCHECK(scheduler);
+
+    return scheduler
+        ->scheduled_wakeup_time_[blink::mojom::BackgroundSyncType::ONE_SHOT];
+  }
+
   void SetUp() override {
     original_client_ = SetBrowserClientForTesting(&browser_client_);
   }
@@ -281,6 +289,7 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_LE(GetBrowserWakeupDelay(blink::mojom::BackgroundSyncType::ONE_SHOT),
             base::TimeDelta::FromSeconds(1));
+  auto wakeup_time1 = GetBrowserWakeupTime();
 
   CancelDelayedProcessing(GURL(kUrl_2),
                           blink::mojom::BackgroundSyncType::ONE_SHOT);
@@ -290,6 +299,7 @@
             base::TimeDelta::FromMinutes(1));
   EXPECT_GT(GetBrowserWakeupDelay(blink::mojom::BackgroundSyncType::ONE_SHOT),
             base::TimeDelta::FromSeconds(1));
+  EXPECT_LT(wakeup_time1, GetBrowserWakeupTime());
 }
 
 #endif
diff --git a/content/browser/frame_host/navigation_request_browsertest.cc b/content/browser/frame_host/navigation_request_browsertest.cc
index 1ff7285..38de5db 100644
--- a/content/browser/frame_host/navigation_request_browsertest.cc
+++ b/content/browser/frame_host/navigation_request_browsertest.cc
@@ -1643,7 +1643,7 @@
 
   EXPECT_TRUE(observer.has_committed());
   EXPECT_TRUE(observer.is_error());
-  EXPECT_EQ(net::ERR_DNS_TIMED_OUT, observer.net_error_code());
+  EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, observer.net_error_code());
   EXPECT_EQ(net::ERR_DNS_TIMED_OUT, observer.resolve_error_info().error);
 }
 
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index ba06a9c..91922e42 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -2603,12 +2603,6 @@
   NOTIMPLEMENTED();
 }
 
-void RenderFrameHostImpl::DocumentOnLoadCompleted() {
-  // This message is only sent for top-level frames. TODO(avi): when frame tree
-  // mirroring works correctly, add a check here to enforce it.
-  delegate_->DocumentOnLoadCompleted(this);
-}
-
 void RenderFrameHostImpl::DidChangeActiveSchedulerTrackedFeatures(
     uint64_t features_mask) {
   renderer_reported_scheduler_tracked_features_ = features_mask;
@@ -3647,6 +3641,14 @@
   }
 }
 
+void RenderFrameHostImpl::DocumentOnLoadCompleted() {
+  // This message is only sent for top-level frames.
+  //
+  // TODO(avi): when frame tree mirroring works correctly, add a check here
+  // to enforce it.
+  delegate_->DocumentOnLoadCompleted(this);
+}
+
 void RenderFrameHostImpl::OnForwardResourceTimingToParent(
     const ResourceTimingInfo& resource_timing) {
   // Don't forward the resource timing if this RFH is pending deletion. This can
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index c99cba0..a196d800 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -1326,6 +1326,7 @@
   void HandleAccessibilityFindInPageResult(
       blink::mojom::FindInPageResultAXParamsPtr params) override;
   void HandleAccessibilityFindInPageTermination() override;
+  void DocumentOnLoadCompleted() override;
 
  protected:
   friend class RenderFrameHostFactory;
@@ -1596,7 +1597,6 @@
   void CancelInitialHistoryLoad() override;
   void UpdateEncoding(const std::string& encoding) override;
   void FrameSizeChanged(const gfx::Size& frame_size) override;
-  void DocumentOnLoadCompleted() override;
   void DidAddMessageToConsole(blink::mojom::ConsoleMessageLevel log_level,
                               const base::string16& message,
                               int32_t line_no,
diff --git a/content/browser/media/session/media_session_impl.cc b/content/browser/media/session/media_session_impl.cc
index a0fb380..fb236fb4 100644
--- a/content/browser/media/session/media_session_impl.cc
+++ b/content/browser/media/session/media_session_impl.cc
@@ -831,6 +831,9 @@
 void MediaSessionImpl::Initialize() {
   delegate_ = AudioFocusDelegate::Create(this);
   delegate_->MediaSessionInfoChanged(GetMediaSessionInfoSync());
+
+  DCHECK(web_contents());
+  DidUpdateFaviconURL(web_contents()->GetFaviconURLs());
 }
 
 AudioFocusDelegate::AudioFocusResult MediaSessionImpl::RequestSystemAudioFocus(
diff --git a/content/browser/media/session/media_session_impl.h b/content/browser/media/session/media_session_impl.h
index 2c14e47..482c1dd 100644
--- a/content/browser/media/session/media_session_impl.h
+++ b/content/browser/media/session/media_session_impl.h
@@ -34,8 +34,6 @@
 #include "base/android/scoped_java_ref.h"
 #endif  // defined(OS_ANDROID)
 
-class MediaSessionImplBrowserTest;
-
 namespace media {
 enum class MediaContentType;
 }  // namespace media
@@ -273,7 +271,7 @@
 
  private:
   friend class content::WebContentsUserData<MediaSessionImpl>;
-  friend class ::MediaSessionImplBrowserTest;
+  friend class MediaSessionImplBrowserTest;
   friend class content::MediaSessionImplVisibilityBrowserTest;
   friend class content::AudioFocusManagerTest;
   friend class content::MediaSessionImplServiceRoutingTest;
diff --git a/content/browser/media/session/media_session_impl_browsertest.cc b/content/browser/media/session/media_session_impl_browsertest.cc
index 237f43690..2133f30 100644
--- a/content/browser/media/session/media_session_impl_browsertest.cc
+++ b/content/browser/media/session/media_session_impl_browsertest.cc
@@ -17,9 +17,11 @@
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/simple_test_tick_clock.h"
 #include "build/build_config.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/media/session/audio_focus_delegate.h"
 #include "content/browser/media/session/mock_media_session_player_observer.h"
 #include "content/browser/media/session/mock_media_session_service_impl.h"
+#include "content/browser/web_contents/web_contents_impl.h"
 #include "content/public/browser/media_session.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/common/favicon_url.h"
@@ -33,14 +35,6 @@
 #include "services/media_session/public/mojom/audio_focus.mojom.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
-using content::WebContents;
-using content::MediaSession;
-using content::MediaSessionImpl;
-using content::AudioFocusDelegate;
-using content::MediaSessionPlayerObserver;
-using content::MediaSessionUmaHelper;
-using content::MockMediaSessionPlayerObserver;
-
 using media_session::mojom::AudioFocusType;
 using media_session::mojom::MediaPlaybackState;
 using media_session::mojom::MediaSessionInfo;
@@ -61,9 +55,10 @@
 
 constexpr gfx::Size kDefaultFaviconSize = gfx::Size(16, 16);
 
-class MockAudioFocusDelegate : public AudioFocusDelegate {
+class MockAudioFocusDelegate : public content::AudioFocusDelegate {
  public:
-  MockAudioFocusDelegate(MediaSessionImpl* media_session, bool async_mode)
+  MockAudioFocusDelegate(content::MediaSessionImpl* media_session,
+                         bool async_mode)
       : media_session_(media_session), async_mode_(async_mode) {}
 
   MOCK_METHOD0(AbandonAudioFocus, void());
@@ -109,7 +104,7 @@
   AudioFocusDelegate::AudioFocusResult sync_result_ =
       AudioFocusDelegate::AudioFocusResult::kSuccess;
 
-  MediaSessionImpl* media_session_;
+  content::MediaSessionImpl* media_session_;
   const bool async_mode_ = false;
 
   std::list<AudioFocusType> requests_;
@@ -118,7 +113,9 @@
 
 }  // namespace
 
-class MediaSessionImplBrowserTest : public content::ContentBrowserTest {
+namespace content {
+
+class MediaSessionImplBrowserTest : public ContentBrowserTest {
  protected:
   MediaSessionImplBrowserTest() = default;
 
@@ -220,9 +217,8 @@
   void SystemStopDucking() { media_session_->StopDucking(); }
 
   void EnsureMediaSessionService() {
-    mock_media_session_service_.reset(
-        new NiceMock<content::MockMediaSessionServiceImpl>(
-            shell()->web_contents()->GetMainFrame()));
+    mock_media_session_service_.reset(new NiceMock<MockMediaSessionServiceImpl>(
+        shell()->web_contents()->GetMainFrame()));
   }
 
   void SetPlaybackState(blink::mojom::MediaSessionPlaybackState state) {
@@ -277,8 +273,7 @@
  protected:
   MediaSessionImpl* media_session_;
   MockAudioFocusDelegate* mock_audio_focus_delegate_;
-  std::unique_ptr<content::MockMediaSessionServiceImpl>
-      mock_media_session_service_;
+  std::unique_ptr<MockMediaSessionServiceImpl> mock_media_session_service_;
 
   DISALLOW_COPY_AND_ASSIGN(MediaSessionImplBrowserTest);
 };
@@ -2479,7 +2474,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(MediaSessionImplBrowserTest, MetadataWhenFileUrlScheme) {
-  base::FilePath path = content::GetTestFilePath(nullptr, "title1.html");
+  base::FilePath path = GetTestFilePath(nullptr, "title1.html");
   GURL file_url = net::FilePathToFileURL(path);
   EXPECT_TRUE(NavigateToURL(shell(), file_url));
 
@@ -2496,27 +2491,24 @@
   valid_sizes.push_back(gfx::Size(100, 100));
   valid_sizes.push_back(gfx::Size(200, 200));
 
-  std::vector<content::FaviconURL> favicons;
-  favicons.push_back(content::FaviconURL(
-      GURL("https://www.example.org/favicon1.png"),
-      content::FaviconURL::IconType::kInvalid, valid_sizes));
-  favicons.push_back(content::FaviconURL(
-      GURL(), content::FaviconURL::IconType::kFavicon, valid_sizes));
-  favicons.push_back(content::FaviconURL(
-      GURL("https://www.example.org/favicon2.png"),
-      content::FaviconURL::IconType::kFavicon, std::vector<gfx::Size>()));
-  favicons.push_back(content::FaviconURL(
-      GURL("https://www.example.org/favicon3.png"),
-      content::FaviconURL::IconType::kFavicon, valid_sizes));
-  favicons.push_back(content::FaviconURL(
-      GURL("https://www.example.org/favicon4.png"),
-      content::FaviconURL::IconType::kTouchIcon, valid_sizes));
-  favicons.push_back(content::FaviconURL(
-      GURL("https://www.example.org/favicon5.png"),
-      content::FaviconURL::IconType::kTouchPrecomposedIcon, valid_sizes));
-  favicons.push_back(content::FaviconURL(
-      GURL("https://www.example.org/favicon6.png"),
-      content::FaviconURL::IconType::kTouchIcon, std::vector<gfx::Size>()));
+  std::vector<FaviconURL> favicons;
+  favicons.push_back(FaviconURL(GURL("https://www.example.org/favicon1.png"),
+                                FaviconURL::IconType::kInvalid, valid_sizes));
+  favicons.push_back(
+      FaviconURL(GURL(), FaviconURL::IconType::kFavicon, valid_sizes));
+  favicons.push_back(FaviconURL(GURL("https://www.example.org/favicon2.png"),
+                                FaviconURL::IconType::kFavicon,
+                                std::vector<gfx::Size>()));
+  favicons.push_back(FaviconURL(GURL("https://www.example.org/favicon3.png"),
+                                FaviconURL::IconType::kFavicon, valid_sizes));
+  favicons.push_back(FaviconURL(GURL("https://www.example.org/favicon4.png"),
+                                FaviconURL::IconType::kTouchIcon, valid_sizes));
+  favicons.push_back(FaviconURL(GURL("https://www.example.org/favicon5.png"),
+                                FaviconURL::IconType::kTouchPrecomposedIcon,
+                                valid_sizes));
+  favicons.push_back(FaviconURL(GURL("https://www.example.org/favicon6.png"),
+                                FaviconURL::IconType::kTouchIcon,
+                                std::vector<gfx::Size>()));
 
   media_session_->DidUpdateFaviconURL(favicons);
 
@@ -2545,7 +2537,7 @@
 
   {
     media_session::test::MockMediaSessionMojoObserver observer(*media_session_);
-    media_session_->DidUpdateFaviconURL(std::vector<content::FaviconURL>());
+    media_session_->DidUpdateFaviconURL(std::vector<FaviconURL>());
     observer.WaitForExpectedImagesOfType(
         media_session::mojom::MediaSessionImageType::kSourceIcon,
         std::vector<media_session::MediaImage>());
@@ -2554,10 +2546,10 @@
 
 IN_PROC_BROWSER_TEST_F(MediaSessionImplBrowserTest,
                        UpdateFaviconURL_ClearOnNavigate) {
-  std::vector<content::FaviconURL> favicons;
-  favicons.push_back(content::FaviconURL(
-      GURL("https://www.example.org/favicon1.png"),
-      content::FaviconURL::IconType::kFavicon, std::vector<gfx::Size>()));
+  std::vector<FaviconURL> favicons;
+  favicons.push_back(FaviconURL(GURL("https://www.example.org/favicon1.png"),
+                                FaviconURL::IconType::kFavicon,
+                                std::vector<gfx::Size>()));
 
   media_session_->DidUpdateFaviconURL(favicons);
 
@@ -2592,6 +2584,69 @@
   }
 }
 
+class MediaSessionFaviconBrowserTest : public ContentBrowserTest {
+ protected:
+  MediaSessionFaviconBrowserTest() = default;
+
+  void SetUpOnMainThread() override {
+    ContentBrowserTest::SetUpOnMainThread();
+
+    host_resolver()->AddRule("*", "127.0.0.1");
+  }
+};
+
+// Helper class that waits to receive a favicon from the renderer process.
+class FaviconWaiter : public WebContentsObserver {
+ public:
+  explicit FaviconWaiter(WebContents* web_contents)
+      : WebContentsObserver(web_contents) {}
+
+  void DidUpdateFaviconURL(const std::vector<FaviconURL>& candidates) override {
+    received_favicon_ = true;
+    run_loop_.Quit();
+  }
+
+  void Wait() {
+    if (received_favicon_)
+      return;
+    run_loop_.Run();
+  }
+
+ private:
+  bool received_favicon_ = false;
+  base::RunLoop run_loop_;
+};
+
+IN_PROC_BROWSER_TEST_F(MediaSessionFaviconBrowserTest, StartupInitalization) {
+  ASSERT_TRUE(embedded_test_server()->Start());
+  EXPECT_TRUE(NavigateToURL(
+      shell(), embedded_test_server()->GetURL("example.com", "/title1.html")));
+
+  std::unique_ptr<FaviconWaiter> favicon_waiter(
+      new FaviconWaiter(shell()->web_contents()));
+
+  // Insert the favicon dynamically.
+  ASSERT_TRUE(content::ExecuteScript(
+      shell()->web_contents(),
+      "let l = document.createElement('link'); "
+      "l.rel='icon'; l.type='image/png'; l.href='single_face.jpg'; "
+      "document.head.appendChild(l)"));
+
+  // Wait until it's received by the browser process.
+  favicon_waiter->Wait();
+
+  // The MediaSession should be created with the favicon already available.
+  MediaSession* media_session = MediaSessionImpl::Get(shell()->web_contents());
+
+  media_session::MediaImage icon;
+  icon.src = embedded_test_server()->GetURL("example.com", "/single_face.jpg");
+  icon.sizes.push_back({16, 16});
+
+  media_session::test::MockMediaSessionMojoObserver observer(*media_session);
+  observer.WaitForExpectedImagesOfType(
+      media_session::mojom::MediaSessionImageType::kSourceIcon, {icon});
+}
+
 IN_PROC_BROWSER_TEST_F(MediaSessionImplBrowserTest,
                        PositionStateRouteWithTwoPlayers) {
   media_session::MediaPosition expected_position(
@@ -2794,3 +2849,5 @@
     observer.WaitForEmptyPosition();
   }
 }
+
+}  // namespace content
diff --git a/content/common/frame.mojom b/content/common/frame.mojom
index dce2284..2d567fe 100644
--- a/content/common/frame.mojom
+++ b/content/common/frame.mojom
@@ -483,10 +483,6 @@
   [EnableIf=is_android]
   UpdateUserGestureCarryoverInfo();
 
-  // Sent after the onload handler has been invoked for the document
-  // in this frame. Sent for top-level frames.
-  DocumentOnLoadCompleted();
-
   // Blink and JavaScript error messages to log to the console or debugger UI.
   DidAddMessageToConsole(
       blink.mojom.ConsoleMessageLevel log_level,
diff --git a/content/public/test/test_host_resolver.cc b/content/public/test/test_host_resolver.cc
index 4c040d2..3d13d11 100644
--- a/content/public/test/test_host_resolver.cc
+++ b/content/public/test/test_host_resolver.cc
@@ -45,6 +45,8 @@
     // queries, rather than perform them.
     // If you really need to make an external DNS query, use
     // net::RuleBasedHostResolverProc and its AllowDirectLookup method.
+    // TODO(crbug.com/1040686): Simulate failure using ERR_NAME_NOT_RESOLVED
+    // rather than ERR_NOT_IMPLEMENTED.
     if (!local) {
       DVLOG(1) << "To avoid external dependencies, simulating failure for "
                   "external DNS lookup of "
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index eb9eb19..6d4992c 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -4709,9 +4709,6 @@
 }
 
 void RenderFrameImpl::DidHandleOnloadEvents() {
-  if (!frame_->Parent()) {
-    GetFrameHost()->DocumentOnLoadCompleted();
-  }
   for (auto& observer : observers_)
     observer.DidHandleOnloadEvents();
 }
diff --git a/content/shell/BUILD.gn b/content/shell/BUILD.gn
index 1b345b7..ca587d4 100644
--- a/content/shell/BUILD.gn
+++ b/content/shell/BUILD.gn
@@ -170,6 +170,8 @@
     "browser/web_test/test_info_extractor.h",
     "browser/web_test/web_test_background_fetch_delegate.cc",
     "browser/web_test/web_test_background_fetch_delegate.h",
+    "browser/web_test/web_test_blink_test_client.cc",
+    "browser/web_test/web_test_blink_test_client.h",
     "browser/web_test/web_test_bluetooth_adapter_provider.cc",
     "browser/web_test/web_test_bluetooth_adapter_provider.h",
     "browser/web_test/web_test_bluetooth_chooser_factory.cc",
diff --git a/content/shell/browser/web_test/blink_test_controller.cc b/content/shell/browser/web_test/blink_test_controller.cc
index d07d6fd..594a585 100644
--- a/content/shell/browser/web_test/blink_test_controller.cc
+++ b/content/shell/browser/web_test/blink_test_controller.cc
@@ -803,28 +803,9 @@
   bool handled = true;
   IPC_BEGIN_MESSAGE_MAP(BlinkTestController, message)
     IPC_MESSAGE_HANDLER(BlinkTestHostMsg_PrintMessage, OnPrintMessage)
-    IPC_MESSAGE_HANDLER(BlinkTestHostMsg_PrintMessageToStderr,
-                        OnPrintMessageToStderr)
-    IPC_MESSAGE_HANDLER(BlinkTestHostMsg_InitiateLayoutDump,
-                        OnInitiateLayoutDump)
     IPC_MESSAGE_HANDLER(BlinkTestHostMsg_OverridePreferences,
                         OnOverridePreferences)
-    IPC_MESSAGE_HANDLER(BlinkTestHostMsg_SetPopupBlockingEnabled,
-                        OnSetPopupBlockingEnabled)
-    IPC_MESSAGE_HANDLER(BlinkTestHostMsg_NavigateSecondaryWindow,
-                        OnNavigateSecondaryWindow)
-    IPC_MESSAGE_HANDLER(BlinkTestHostMsg_GoToOffset, OnGoToOffset)
-    IPC_MESSAGE_HANDLER(BlinkTestHostMsg_Reload, OnReload)
-    IPC_MESSAGE_HANDLER(BlinkTestHostMsg_LoadURLForFrame, OnLoadURLForFrame)
-    IPC_MESSAGE_HANDLER(BlinkTestHostMsg_CloseRemainingWindows,
-                        OnCloseRemainingWindows)
     IPC_MESSAGE_HANDLER(BlinkTestHostMsg_ResetDone, OnResetDone)
-    IPC_MESSAGE_HANDLER(BlinkTestHostMsg_SetBluetoothManualChooser,
-                        OnSetBluetoothManualChooser)
-    IPC_MESSAGE_HANDLER(BlinkTestHostMsg_GetBluetoothManualChooserEvents,
-                        OnGetBluetoothManualChooserEvents)
-    IPC_MESSAGE_HANDLER(BlinkTestHostMsg_SendBluetoothManualChooserEvent,
-                        OnSendBluetoothManualChooserEvent)
     IPC_MESSAGE_HANDLER(WebTestHostMsg_BlockThirdPartyCookies,
                         OnBlockThirdPartyCookies)
     IPC_MESSAGE_UNHANDLED(handled = false)
diff --git a/content/shell/browser/web_test/blink_test_controller.h b/content/shell/browser/web_test/blink_test_controller.h
index 4b62a9f..57dfac9 100644
--- a/content/shell/browser/web_test/blink_test_controller.h
+++ b/content/shell/browser/web_test/blink_test_controller.h
@@ -184,6 +184,20 @@
     return accumulated_web_test_runtime_flags_changes_;
   }
 
+  void OnInitiateLayoutDump();
+  void OnResetDone();
+  void OnPrintMessageToStderr(const std::string& message);
+  void OnReload();
+  void OnCloseRemainingWindows();
+  void OnGoToOffset(int offset);
+  void OnSetBluetoothManualChooser(bool enable);
+  void OnGetBluetoothManualChooserEvents();
+  void OnSendBluetoothManualChooserEvent(const std::string& event,
+                                         const std::string& argument);
+  void OnSetPopupBlockingEnabled(bool block_popups);
+  void OnLoadURLForFrame(const GURL& url, const std::string& frame_name);
+  void OnNavigateSecondaryWindow(const GURL& url);
+
  private:
   enum TestPhase { BETWEEN_TESTS, DURING_TEST, CLEAN_UP };
 
@@ -211,26 +225,13 @@
   void OnAudioDump(const std::vector<unsigned char>& audio_dump);
   void OnImageDump(const std::string& actual_pixel_hash, const SkBitmap& image);
   void OnTextDump(const std::string& dump);
-  void OnInitiateLayoutDump();
   void OnDumpFrameLayoutResponse(int frame_tree_node_id,
                                  const std::string& dump);
-  void OnPrintMessageToStderr(const std::string& message);
   void OnPrintMessage(const std::string& message);
   void OnOverridePreferences(const WebPreferences& prefs);
-  void OnSetPopupBlockingEnabled(bool block_popups);
   void OnTestFinished();
-  void OnNavigateSecondaryWindow(const GURL& url);
-  void OnGoToOffset(int offset);
-  void OnReload();
-  void OnLoadURLForFrame(const GURL& url, const std::string& frame_name);
   void OnCaptureSessionHistory();
-  void OnCloseRemainingWindows();
-  void OnResetDone();
   void OnLeakDetectionDone(const LeakDetector::LeakDetectionReport& report);
-  void OnSetBluetoothManualChooser(bool enable);
-  void OnGetBluetoothManualChooserEvents();
-  void OnSendBluetoothManualChooserEvent(const std::string& event,
-                                         const std::string& argument);
   void OnBlockThirdPartyCookies(bool block);
   mojo::AssociatedRemote<mojom::WebTestControl>& GetWebTestControlRemote(
       RenderFrameHost* frame);
diff --git a/content/shell/browser/web_test/web_test_blink_test_client.cc b/content/shell/browser/web_test/web_test_blink_test_client.cc
new file mode 100644
index 0000000..b23aae5
--- /dev/null
+++ b/content/shell/browser/web_test/web_test_blink_test_client.cc
@@ -0,0 +1,72 @@
+// 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 "content/shell/browser/web_test/web_test_blink_test_client.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+
+#include "content/shell/browser/web_test/blink_test_controller.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
+
+namespace content {
+
+// static
+void WebTestBlinkTestClient::Create(
+    mojo::PendingReceiver<mojom::WebTestClient> receiver) {
+  mojo::MakeSelfOwnedReceiver(std::make_unique<WebTestBlinkTestClient>(),
+                              std::move(receiver));
+}
+
+void WebTestBlinkTestClient::InitiateLayoutDump() {
+  BlinkTestController::Get()->OnInitiateLayoutDump();
+}
+
+void WebTestBlinkTestClient::PrintMessageToStderr(const std::string& message) {
+  BlinkTestController::Get()->OnPrintMessageToStderr(message);
+}
+
+void WebTestBlinkTestClient::Reload() {
+  BlinkTestController::Get()->OnReload();
+}
+
+void WebTestBlinkTestClient::CloseRemainingWindows() {
+  BlinkTestController::Get()->OnCloseRemainingWindows();
+}
+
+void WebTestBlinkTestClient::GoToOffset(int offset) {
+  BlinkTestController::Get()->OnGoToOffset(offset);
+}
+
+void WebTestBlinkTestClient::SendBluetoothManualChooserEvent(
+    const std::string& event,
+    const std::string& argument) {
+  BlinkTestController::Get()->OnSendBluetoothManualChooserEvent(event,
+                                                                argument);
+}
+
+void WebTestBlinkTestClient::SetBluetoothManualChooser(bool enable) {
+  BlinkTestController::Get()->OnSetBluetoothManualChooser(enable);
+}
+
+void WebTestBlinkTestClient::GetBluetoothManualChooserEvents() {
+  BlinkTestController::Get()->OnGetBluetoothManualChooserEvents();
+}
+
+void WebTestBlinkTestClient::SetPopupBlockingEnabled(bool block_popups) {
+  BlinkTestController::Get()->OnSetPopupBlockingEnabled(block_popups);
+}
+
+void WebTestBlinkTestClient::LoadURLForFrame(const GURL& url,
+                                             const std::string& frame_name) {
+  BlinkTestController::Get()->OnLoadURLForFrame(url, frame_name);
+}
+
+void WebTestBlinkTestClient::NavigateSecondaryWindow(const GURL& url) {
+  BlinkTestController::Get()->OnNavigateSecondaryWindow(url);
+}
+
+}  // namespace content
diff --git a/content/shell/browser/web_test/web_test_blink_test_client.h b/content/shell/browser/web_test/web_test_blink_test_client.h
new file mode 100644
index 0000000..bea0c79
--- /dev/null
+++ b/content/shell/browser/web_test/web_test_blink_test_client.h
@@ -0,0 +1,42 @@
+// Copyright 2020 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_SHELL_BROWSER_WEB_TEST_WEB_TEST_BLINK_TEST_CLIENT_H_
+#define CONTENT_SHELL_BROWSER_WEB_TEST_WEB_TEST_BLINK_TEST_CLIENT_H_
+
+#include "base/macros.h"
+#include "content/shell/common/web_test.mojom.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "url/gurl.h"
+
+namespace content {
+
+class WebTestBlinkTestClient : public mojom::WebTestClient {
+ public:
+  WebTestBlinkTestClient() = default;
+  ~WebTestBlinkTestClient() override = default;
+
+  static void Create(mojo::PendingReceiver<mojom::WebTestClient> receiver);
+
+ private:
+  // WebTestClient implementation.
+  void InitiateLayoutDump() override;
+  void PrintMessageToStderr(const std::string& message) override;
+  void Reload() override;
+  void CloseRemainingWindows() override;
+  void GoToOffset(int offset) override;
+  void SendBluetoothManualChooserEvent(const std::string& event,
+                                       const std::string& argument) override;
+  void SetBluetoothManualChooser(bool enable) override;
+  void GetBluetoothManualChooserEvents() override;
+  void SetPopupBlockingEnabled(bool block_popups) override;
+  void LoadURLForFrame(const GURL& url, const std::string& frame_name) override;
+  void NavigateSecondaryWindow(const GURL& url) override;
+
+  DISALLOW_COPY_AND_ASSIGN(WebTestBlinkTestClient);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_SHELL_BROWSER_WEB_TEST_WEB_TEST_BLINK_TEST_CLIENT_H_
diff --git a/content/shell/browser/web_test/web_test_content_browser_client.cc b/content/shell/browser/web_test/web_test_content_browser_client.cc
index 62ae14ae..4497b2d0 100644
--- a/content/shell/browser/web_test/web_test_content_browser_client.cc
+++ b/content/shell/browser/web_test/web_test_content_browser_client.cc
@@ -30,6 +30,7 @@
 #include "content/shell/browser/web_test/fake_bluetooth_chooser.h"
 #include "content/shell/browser/web_test/fake_bluetooth_chooser_factory.h"
 #include "content/shell/browser/web_test/mojo_web_test_helper.h"
+#include "content/shell/browser/web_test/web_test_blink_test_client.h"
 #include "content/shell/browser/web_test/web_test_bluetooth_fake_adapter_setter_impl.h"
 #include "content/shell/browser/web_test/web_test_browser_context.h"
 #include "content/shell/browser/web_test/web_test_browser_main_parts.h"
@@ -156,6 +157,9 @@
       base::BindRepeating(&WebTestBluetoothFakeAdapterSetterImpl::Create),
       ui_task_runner);
 
+  registry->AddInterface(base::BindRepeating(&WebTestBlinkTestClient::Create),
+                         ui_task_runner);
+
   registry->AddInterface(base::BindRepeating(&bluetooth::FakeBluetooth::Create),
                          ui_task_runner);
   // This class outlives |render_process_host|, which owns |registry|. Since
diff --git a/content/shell/common/web_test.mojom b/content/shell/common/web_test.mojom
index bab5d6f..bcccfbf 100644
--- a/content/shell/common/web_test.mojom
+++ b/content/shell/common/web_test.mojom
@@ -49,6 +49,7 @@
   gfx.mojom.Rect selection_rect;
 };
 
+// Blink test messages sent from the browser process to the renderer.
 interface WebTestControl {
   CaptureDump() => (WebTestDump result);
 
@@ -85,3 +86,49 @@
   // Reply Bluetooth manual events to BlinkTestRunner.
   ReplyBluetoothManualChooserEvents(array<string> events);
 };
+
+// Blink test messages sent from the renderer process to the browser.
+interface WebTestClient {
+  // Asks the browser process to perform a layout dump spanning all the
+  // (potentially cross-process) frames.  This goes through multiple
+  // WebTestControl.DumpFrameLayout calls and ends with sending of
+  // BlinkTestMsg_LayoutDumpCompleted.
+  InitiateLayoutDump();
+
+  // Add a message to stderr (not saved to expected output files, for debugging
+  // only).
+  PrintMessageToStderr(string message);
+
+  // Trigger a reload navigation on the main WebView.
+  Reload();
+
+  // Invoked when the embedder should close all but the main WebView.
+  CloseRemainingWindows();
+
+  // Trigger a GoToOffset navigation on the main WebView.
+  GoToOffset(int32 offset);
+
+  // Calls the BluetoothChooser::EventHandler with the arguments here. Valid
+  // event strings are:
+  //  * "cancel" - simulates the user canceling the chooser.
+  //  * "select" - simulates the user selecting a device whose device ID is in
+  //               |argument|.
+  SendBluetoothManualChooserEvent(string event, string argument);
+
+  // If |enable| is true makes the Bluetooth chooser record its input and wait
+  // for instructions from the test program on how to proceed. Otherwise
+  // fall backs to the browser's default chooser.
+  SetBluetoothManualChooser(bool enable);
+
+  // Returns the events recorded since the last call to this function.
+  GetBluetoothManualChooserEvents();
+
+  // Manages the popup blocking setting to used for web tests.
+  SetPopupBlockingEnabled(bool block_popups);
+
+  // Trigger a loadURL navigation on the main WebView.
+  LoadURLForFrame(url.mojom.Url url, string frame_name);
+
+  // Naivgate a URL on the secondary window.
+  NavigateSecondaryWindow(url.mojom.Url url);
+};
diff --git a/content/shell/common/web_test/blink_test_messages.h b/content/shell/common/web_test/blink_test_messages.h
index 3bccc2b..5080ab24 100644
--- a/content/shell/common/web_test/blink_test_messages.h
+++ b/content/shell/common/web_test/blink_test_messages.h
@@ -15,37 +15,11 @@
 
 #define IPC_MESSAGE_START BlinkTestMsgStart
 
-// Asks the browser process to perform a layout dump spanning all the
-// (potentially cross-process) frames.  This goes through multiple
-// WebTestControl.DumpFrameLayout calls and ends with sending of
-// LayoutDumpCompleted.
-// TODO(crbug.com/1039247): LayoutDumpCompleted call should be removed and the
-// callback should happen part of LayoutDump call on the host interface.
-IPC_MESSAGE_ROUTED0(BlinkTestHostMsg_InitiateLayoutDump)
-
 IPC_MESSAGE_ROUTED0(BlinkTestHostMsg_ResetDone)
 
 // WebTestDelegate related.
 IPC_MESSAGE_ROUTED1(BlinkTestHostMsg_OverridePreferences,
                     content::WebPreferences /* preferences */)
 IPC_MESSAGE_ROUTED1(BlinkTestHostMsg_PrintMessage, std::string /* message */)
-IPC_MESSAGE_ROUTED1(BlinkTestHostMsg_PrintMessageToStderr,
-                    std::string /* message */)
-IPC_MESSAGE_ROUTED1(BlinkTestHostMsg_NavigateSecondaryWindow, GURL /* url */)
-IPC_MESSAGE_ROUTED1(BlinkTestHostMsg_GoToOffset, int /* offset */)
-IPC_MESSAGE_ROUTED0(BlinkTestHostMsg_Reload)
-IPC_MESSAGE_ROUTED2(BlinkTestHostMsg_LoadURLForFrame,
-                    GURL /* url */,
-                    std::string /* frame_name */)
-IPC_MESSAGE_ROUTED0(BlinkTestHostMsg_CloseRemainingWindows)
-
-IPC_MESSAGE_ROUTED1(BlinkTestHostMsg_SetBluetoothManualChooser,
-                    bool /* enable */)
-IPC_MESSAGE_ROUTED0(BlinkTestHostMsg_GetBluetoothManualChooserEvents)
-IPC_MESSAGE_ROUTED2(BlinkTestHostMsg_SendBluetoothManualChooserEvent,
-                    std::string /* event */,
-                    std::string /* argument */)
-IPC_MESSAGE_ROUTED1(BlinkTestHostMsg_SetPopupBlockingEnabled,
-                    bool /* block_popups */)
 
 #endif  // CONTENT_SHELL_COMMON_WEB_TEST_BLINK_TEST_MESSAGES_H_
diff --git a/content/shell/renderer/web_test/blink_test_runner.cc b/content/shell/renderer/web_test/blink_test_runner.cc
index 2e88791..4d82037 100644
--- a/content/shell/renderer/web_test/blink_test_runner.cc
+++ b/content/shell/renderer/web_test/blink_test_runner.cc
@@ -182,7 +182,7 @@
 }
 
 void BlinkTestRunner::PrintMessageToStderr(const std::string& message) {
-  Send(new BlinkTestHostMsg_PrintMessageToStderr(routing_id(), message));
+  GetWebTestClientRemote().PrintMessageToStderr(message);
 }
 
 void BlinkTestRunner::PrintMessage(const std::string& message) {
@@ -260,8 +260,7 @@
 }
 
 void BlinkTestRunner::SetPopupBlockingEnabled(bool block_popups) {
-  Send(
-      new BlinkTestHostMsg_SetPopupBlockingEnabled(routing_id(), block_popups));
+  GetWebTestClientRemote().SetPopupBlockingEnabled(block_popups);
 }
 
 void BlinkTestRunner::UseUnfortunateSynchronousResizeMode(bool enable) {
@@ -289,7 +288,7 @@
 }
 
 void BlinkTestRunner::NavigateSecondaryWindow(const GURL& url) {
-  Send(new BlinkTestHostMsg_NavigateSecondaryWindow(routing_id(), url));
+  GetWebTestClientRemote().NavigateSecondaryWindow(url);
 }
 
 void BlinkTestRunner::InspectSecondaryWindow() {
@@ -358,20 +357,19 @@
 }
 
 void BlinkTestRunner::SetBluetoothManualChooser(bool enable) {
-  Send(new BlinkTestHostMsg_SetBluetoothManualChooser(routing_id(), enable));
+  GetWebTestClientRemote().SetBluetoothManualChooser(enable);
 }
 
 void BlinkTestRunner::GetBluetoothManualChooserEvents(
     base::OnceCallback<void(const std::vector<std::string>&)> callback) {
   get_bluetooth_events_callbacks_.push_back(std::move(callback));
-  Send(new BlinkTestHostMsg_GetBluetoothManualChooserEvents(routing_id()));
+  GetWebTestClientRemote().GetBluetoothManualChooserEvents();
 }
 
 void BlinkTestRunner::SendBluetoothManualChooserEvent(
     const std::string& event,
     const std::string& argument) {
-  Send(new BlinkTestHostMsg_SendBluetoothManualChooserEvent(routing_id(), event,
-                                                            argument));
+  GetWebTestClientRemote().SendBluetoothManualChooserEvent(event, argument);
 }
 
 void BlinkTestRunner::SetFocus(blink::WebView* web_view, bool focus) {
@@ -527,7 +525,7 @@
     // TODO(vmpstr): Since CaptureDump is called from the browser, we can be
     // smart and move this logic directly to the browser.
     waiting_for_layout_dump_results_ = true;
-    Send(new BlinkTestHostMsg_InitiateLayoutDump(routing_id()));
+    GetWebTestClientRemote().InitiateLayoutDump();
   }
 }
 
@@ -588,7 +586,7 @@
 }
 
 void BlinkTestRunner::CloseRemainingWindows() {
-  Send(new BlinkTestHostMsg_CloseRemainingWindows(routing_id()));
+  GetWebTestClientRemote().CloseRemainingWindows();
 }
 
 void BlinkTestRunner::DeleteAllCookies() {
@@ -600,16 +598,16 @@
 }
 
 void BlinkTestRunner::GoToOffset(int offset) {
-  Send(new BlinkTestHostMsg_GoToOffset(routing_id(), offset));
+  GetWebTestClientRemote().GoToOffset(offset);
 }
 
 void BlinkTestRunner::Reload() {
-  Send(new BlinkTestHostMsg_Reload(routing_id()));
+  GetWebTestClientRemote().Reload();
 }
 
 void BlinkTestRunner::LoadURLForFrame(const WebURL& url,
                                       const std::string& frame_name) {
-  Send(new BlinkTestHostMsg_LoadURLForFrame(routing_id(), url, frame_name));
+  GetWebTestClientRemote().LoadURLForFrame(url, frame_name);
 }
 
 bool BlinkTestRunner::AllowExternalPages() {
@@ -740,6 +738,14 @@
   return *bluetooth_fake_adapter_setter_;
 }
 
+mojom::WebTestClient& BlinkTestRunner::GetWebTestClientRemote() {
+  if (!web_test_client_remote_) {
+    RenderThread::Get()->BindHostReceiver(
+        web_test_client_remote_.BindNewPipeAndPassReceiver());
+  }
+  return *web_test_client_remote_;
+}
+
 void BlinkTestRunner::OnSetupSecondaryRenderer() {
   DCHECK(!is_main_window_);
 
diff --git a/content/shell/renderer/web_test/blink_test_runner.h b/content/shell/renderer/web_test/blink_test_runner.h
index abf4eba..0266180 100644
--- a/content/shell/renderer/web_test/blink_test_runner.h
+++ b/content/shell/renderer/web_test/blink_test_runner.h
@@ -180,6 +180,9 @@
   mojo::Remote<mojom::WebTestBluetoothFakeAdapterSetter>
       bluetooth_fake_adapter_setter_;
 
+  mojom::WebTestClient& GetWebTestClientRemote();
+  mojo::Remote<mojom::WebTestClient> web_test_client_remote_;
+
   test_runner::TestPreferences prefs_;
 
   mojom::ShellTestConfigurationPtr test_config_;
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index d4deef7..a7dfe19 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1081,6 +1081,7 @@
     "//components/discardable_memory/client",
     "//components/discardable_memory/common",
     "//components/discardable_memory/service",
+    "//components/favicon/content",
     "//components/network_session_configurator/common",
     "//components/payments/mojom",
     "//components/services/quarantine:test_support",
diff --git a/content/test/data/gpu/pixel_reflected_div.html b/content/test/data/gpu/pixel_reflected_div.html
new file mode 100644
index 0000000..a401a200
--- /dev/null
+++ b/content/test/data/gpu/pixel_reflected_div.html
@@ -0,0 +1,43 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+<meta name="viewport" content="initial-scale=1">
+<title>A div with its reflection below which results in multiple render passes</title>
+<style type="text/css">
+body {
+  margin: 0px auto;
+}
+
+/* Both will-change and -webkit-box-reflect are needed to ensure multiple render
+   passes. */
+#main {
+  position: absolute;
+  background-color: #FF8000;
+  width: 100px;
+  height: 400px;
+  will-change: transform;
+  -webkit-box-reflect: below 100px;
+}
+</style>
+<script>
+var frame = 0;
+
+// It's necessary to do an animation prior to sending SUCCESS in order to
+// reliably reproduce https://crbug.com/1033279.
+function animate() {
+  frame++;
+  document.getElementById('main').style.top = '-' + frame + 'px';
+  if (frame == 300) {
+    domAutomationController.send("SUCCESS");
+    return;
+  }
+  // Use setTimeout() because window.requestAnimationFrame() doesn't reliably
+  // reproduce https://crbug.com/1033279.
+  setTimeout(animate, 20);
+}
+</script>
+</head>
+<body onload="animate()">
+<div id="main"></div>
+</body>
+</html>
diff --git a/content/test/gpu/gpu_tests/pixel_test_pages.py b/content/test/gpu/gpu_tests/pixel_test_pages.py
index 01271d4..9b3f3a5 100644
--- a/content/test/gpu/gpu_tests/pixel_test_pages.py
+++ b/content/test/gpu/gpu_tests/pixel_test_pages.py
@@ -151,6 +151,31 @@
         test_rect=[20, 20, 370, 370]),
 
       PixelTestPage(
+        'pixel_reflected_div.html',
+        base_name + '_ReflectedDiv',
+        test_rect=[0, 0, 100, 300],
+        expected_colors=[
+          {
+            'comment': 'inside original div, orange',
+            'location': [0, 0],
+            'size': [100, 99],
+            'color': [255, 128, 0],
+          },
+          {
+            'comment': 'outside both div and reflection, in between, white',
+            'location': [0, 101],
+            'size': [100, 98],
+            'color': [255, 255, 255],
+          },
+          {
+            'comment': 'inside reflection, orange',
+            'location': [0, 201],
+            'size': [100, 99],
+            'color': [255, 128, 0],
+          }
+        ]),
+
+      PixelTestPage(
         'pixel_canvas2d.html',
         base_name + '_Canvas2DRedBox',
         test_rect=[0, 0, 300, 300]),
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
index ea78514..ffc3aca7 100644
--- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
+++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -552,6 +552,8 @@
 crbug.com/957807 [ chromeos ] conformance/uniforms/uniform-samplers-test.html [ Skip ]
 crbug.com/957807 [ chromeos ] deqp/data/gles2/shaders/conversions.html [ Skip ]
 crbug.com/957807 [ chromeos ] deqp/data/gles2/shaders/swizzles.html [ Skip ]
+# There is a crash, likely in this test, causing all following tests in the shard to fail.
+crbug.com/1043953 [ chromeos ] conformance/textures/misc/texture-size-limit.html [ Skip ]
 
 # ChromeOS: AMD
 crbug.com/995652 [ chromeos amd ] conformance/uniforms/out-of-bounds-uniform-array-access.html [ Skip ]
diff --git a/content/test/test_render_frame.cc b/content/test/test_render_frame.cc
index f384d4159..cc1f1ff 100644
--- a/content/test/test_render_frame.cc
+++ b/content/test/test_render_frame.cc
@@ -168,8 +168,6 @@
 
   void CancelInitialHistoryLoad() override {}
 
-  void DocumentOnLoadCompleted() override {}
-
   void UpdateEncoding(const std::string& encoding_name) override {}
 
   void FrameSizeChanged(const gfx::Size& frame_size) override {}
diff --git a/extensions/browser/api/declarative_net_request/composite_matcher.cc b/extensions/browser/api/declarative_net_request/composite_matcher.cc
index 9db8fab..eed6e9f 100644
--- a/extensions/browser/api/declarative_net_request/composite_matcher.cc
+++ b/extensions/browser/api/declarative_net_request/composite_matcher.cc
@@ -9,6 +9,8 @@
 #include <utility>
 
 #include "base/metrics/histogram_macros.h"
+#include "base/time/time.h"
+#include "base/timer/elapsed_timer.h"
 #include "extensions/browser/api/declarative_net_request/flat/extension_ruleset_generated.h"
 #include "extensions/browser/api/declarative_net_request/request_action.h"
 #include "extensions/browser/api/declarative_net_request/request_params.h"
@@ -44,6 +46,22 @@
   return true;
 }
 
+// Helper to log the time taken in CompositeMatcher::GetBeforeRequestAction.
+class ScopedGetBeforeRequestActionTimer {
+ public:
+  ScopedGetBeforeRequestActionTimer() = default;
+  ~ScopedGetBeforeRequestActionTimer() {
+    UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
+        "Extensions.DeclarativeNetRequest.EvaluateBeforeRequestTime."
+        "SingleExtension2",
+        timer_.Elapsed(), base::TimeDelta::FromMicroseconds(1),
+        base::TimeDelta::FromMilliseconds(50), 50);
+  }
+
+ private:
+  base::ElapsedTimer timer_;
+};
+
 }  // namespace
 
 ActionInfo::ActionInfo(base::Optional<RequestAction> action,
@@ -92,10 +110,7 @@
 ActionInfo CompositeMatcher::GetBeforeRequestAction(
     const RequestParams& params,
     PageAccess page_access) const {
-  // TODO(karandeepb): change this to report time in micro-seconds.
-  SCOPED_UMA_HISTOGRAM_TIMER(
-      "Extensions.DeclarativeNetRequest.EvaluateBeforeRequestTime."
-      "SingleExtension");
+  ScopedGetBeforeRequestActionTimer timer;
 
   bool notify_request_withheld = false;
   for (const auto& matcher : matchers_) {
diff --git a/extensions/browser/api/declarative_net_request/ruleset_manager.cc b/extensions/browser/api/declarative_net_request/ruleset_manager.cc
index f3b58de..9c021db 100644
--- a/extensions/browser/api/declarative_net_request/ruleset_manager.cc
+++ b/extensions/browser/api/declarative_net_request/ruleset_manager.cc
@@ -13,6 +13,8 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/optional.h"
 #include "base/stl_util.h"
+#include "base/time/time.h"
+#include "base/timer/elapsed_timer.h"
 #include "components/web_cache/browser/web_cache_manager.h"
 #include "extensions/browser/api/declarative_net_request/composite_matcher.h"
 #include "extensions/browser/api/declarative_net_request/constants.h"
@@ -167,6 +169,21 @@
       request.render_process_id, request.frame_id, extension_id);
 }
 
+// Helper to log the time taken in RulesetManager::EvaluateRequestInternal.
+class ScopedEvaluateRequestTimer {
+ public:
+  ScopedEvaluateRequestTimer() = default;
+  ~ScopedEvaluateRequestTimer() {
+    UMA_HISTOGRAM_CUSTOM_MICROSECONDS_TIMES(
+        "Extensions.DeclarativeNetRequest.EvaluateRequestTime.AllExtensions3",
+        timer_.Elapsed(), base::TimeDelta::FromMicroseconds(1),
+        base::TimeDelta::FromMilliseconds(50), 50);
+  }
+
+ private:
+  base::ElapsedTimer timer_;
+};
+
 }  // namespace
 
 RulesetManager::RulesetManager(content::BrowserContext* browser_context)
@@ -451,8 +468,7 @@
   if (rulesets_.empty())
     return actions;
 
-  SCOPED_UMA_HISTOGRAM_TIMER(
-      "Extensions.DeclarativeNetRequest.EvaluateRequestTime.AllExtensions2");
+  ScopedEvaluateRequestTimer timer;
 
   const RequestParams params(request);
   const int tab_id = request.frame_data.tab_id;
diff --git a/extensions/browser/api/dns/dns_apitest.cc b/extensions/browser/api/dns/dns_apitest.cc
index 4e88dd6..10974fc 100644
--- a/extensions/browser/api/dns/dns_apitest.cc
+++ b/extensions/browser/api/dns/dns_apitest.cc
@@ -128,7 +128,7 @@
   network::DnsLookupResult result2 =
       network::BlockingDnsLookup(network_context, host_port_pair,
                                  std::move(params), net::NetworkIsolationKey());
-  EXPECT_EQ(net::ERR_DNS_CACHE_MISS, result2.error);
+  EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, result2.error);
 }
 
 IN_PROC_BROWSER_TEST_F(DnsApiTest, DnsExtension) {
diff --git a/extensions/browser/api/sockets_tcp/sockets_tcp_apitest.cc b/extensions/browser/api/sockets_tcp/sockets_tcp_apitest.cc
index 2f8fa8f..c71e5de 100644
--- a/extensions/browser/api/sockets_tcp/sockets_tcp_apitest.cc
+++ b/extensions/browser/api/sockets_tcp/sockets_tcp_apitest.cc
@@ -132,7 +132,7 @@
   network::DnsLookupResult result2 =
       network::BlockingDnsLookup(network_context, host_port_pair,
                                  std::move(params), net::NetworkIsolationKey());
-  EXPECT_EQ(net::ERR_DNS_CACHE_MISS, result2.error);
+  EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, result2.error);
 }
 
 IN_PROC_BROWSER_TEST_F(SocketsTcpApiTest, SocketTcpExtensionTLS) {
diff --git a/extensions/browser/computed_hashes.cc b/extensions/browser/computed_hashes.cc
index 1c3bf0c..4139bb15 100644
--- a/extensions/browser/computed_hashes.cc
+++ b/extensions/browser/computed_hashes.cc
@@ -45,6 +45,54 @@
 
 }  // namespace
 
+ComputedHashes::Data::Data() = default;
+ComputedHashes::Data::~Data() = default;
+ComputedHashes::Data::Data(ComputedHashes::Data&& data) = default;
+ComputedHashes::Data& ComputedHashes::Data::operator=(
+    ComputedHashes::Data&& data) = default;
+
+ComputedHashes::Data::HashInfo::HashInfo(int block_size,
+                                         std::vector<std::string> hashes,
+                                         base::FilePath relative_unix_path)
+    : block_size(block_size),
+      hashes(std::move(hashes)),
+      relative_unix_path(std::move(relative_unix_path)) {}
+ComputedHashes::Data::HashInfo::~HashInfo() = default;
+
+ComputedHashes::Data::HashInfo::HashInfo(ComputedHashes::Data::HashInfo&&) =
+    default;
+ComputedHashes::Data::HashInfo& ComputedHashes::Data::HashInfo::operator=(
+    ComputedHashes::Data::HashInfo&&) = default;
+
+const ComputedHashes::Data::HashInfo* ComputedHashes::Data::GetItem(
+    const base::FilePath& relative_path) const {
+  base::FilePath::StringType canonicalized_path =
+      content_verifier_utils::CanonicalizeRelativePath(relative_path);
+  auto iter = items_.find(canonicalized_path);
+  return iter == items_.end() ? nullptr : &iter->second;
+}
+
+void ComputedHashes::Data::Add(const base::FilePath& relative_path,
+                               int block_size,
+                               std::vector<std::string> hashes) {
+  base::FilePath::StringType canonicalized_path =
+      content_verifier_utils::CanonicalizeRelativePath(relative_path);
+  items_.insert(
+      std::make_pair(canonicalized_path,
+                     HashInfo(block_size, std::move(hashes),
+                              relative_path.NormalizePathSeparatorsTo('/'))));
+}
+
+void ComputedHashes::Data::Remove(const base::FilePath& relative_path) {
+  base::FilePath::StringType canonicalized_path =
+      content_verifier_utils::CanonicalizeRelativePath(relative_path);
+  items_.erase(canonicalized_path);
+}
+
+const std::map<base::FilePath::StringType, ComputedHashes::Data::HashInfo>&
+ComputedHashes::Data::items() const {
+  return items_;
+}
 
 ComputedHashes::ComputedHashes(Data&& data) : data_(std::move(data)) {}
 ComputedHashes::~ComputedHashes() = default;
@@ -102,8 +150,6 @@
 
     base::FilePath relative_path =
         base::FilePath::FromUTF8Unsafe(*relative_path_utf8);
-    relative_path = relative_path.NormalizePathSeparatorsTo('/');
-
     std::vector<std::string> hashes;
 
     for (const base::Value& value : block_hashes->GetList()) {
@@ -116,7 +162,7 @@
       if (!base::Base64Decode(encoded, decoded))
         return base::nullopt;
     }
-    data[relative_path] = HashInfo(*block_size, std::move(hashes));
+    data.Add(relative_path, *block_size, std::move(hashes));
   }
   uma_recorder.RecordSuccess();
   return ComputedHashes(std::move(data));
@@ -144,23 +190,21 @@
 
   // Now iterate over all the paths in sorted order and compute the block hashes
   // for each one.
-  std::map<base::FilePath, HashInfo> data;
+  Data data;
   for (const auto& full_path : paths) {
     if (is_cancelled && is_cancelled.Run())
       return base::nullopt;
 
-    base::FilePath relative_unix_path;
-    extension_root.AppendRelativePath(full_path, &relative_unix_path);
-    relative_unix_path = relative_unix_path.NormalizePathSeparatorsTo('/');
+    base::FilePath relative_path;
+    extension_root.AppendRelativePath(full_path, &relative_path);
 
-    if (!should_compute_hashes_for_resource.Run(relative_unix_path))
+    if (!should_compute_hashes_for_resource.Run(relative_path))
       continue;
 
     base::Optional<std::vector<std::string>> hashes =
-        ComputeAndCheckResourceHash(full_path, relative_unix_path, block_size);
+        ComputeAndCheckResourceHash(full_path, block_size);
     if (hashes)
-      data[relative_unix_path] =
-          HashInfo(block_size, std::move(hashes.value()));
+      data.Add(relative_path, block_size, std::move(hashes.value()));
   }
 
   return data;
@@ -169,50 +213,12 @@
 bool ComputedHashes::GetHashes(const base::FilePath& relative_path,
                                int* block_size,
                                std::vector<std::string>* hashes) const {
-  base::FilePath path = relative_path.NormalizePathSeparatorsTo('/');
-  // TODO(lazyboy): Align treatment of |data_| with that of
-  // VerifiedContents::root_hashes_, so that we don't have to perform the linear
-  // lookup below.
-  auto find_data = [&](const base::FilePath& normalized_path) {
-    auto i = data_.find(normalized_path);
-    if (i == data_.end() &&
-        !content_verifier_utils::IsFileAccessCaseSensitive()) {
-      // If we didn't find the entry using exact match, it's possible the
-      // developer is using a path with some letters in the incorrect case,
-      // which happens to work on windows/osx. So try doing a linear scan to
-      // look for a case-insensitive match. In practice most extensions don't
-      // have that big a list of files so the performance penalty is probably
-      // not too big here. Also for crbug.com/29941 we plan to start warning
-      // developers when they are making this mistake, since their extension
-      // will be broken on linux/chromeos.
-      for (i = data_.begin(); i != data_.end(); ++i) {
-        const base::FilePath& entry = i->first;
-        if (base::FilePath::CompareEqualIgnoreCase(entry.value(),
-                                                   normalized_path.value())) {
-          break;
-        }
-      }
-    }
-    return i;
-  };
-  auto i = find_data(path);
-  if (i == data_.end() &&
-      content_verifier_utils::IsDotSpaceFilenameSuffixIgnored()) {
-    base::FilePath::StringType trimmed_path_value;
-    // Also search for path with (.| )+ suffix trimmed as they are ignored in
-    // windows. This matches the canonicalization behavior of
-    // VerifiedContents::Create.
-    if (content_verifier_utils::TrimDotSpaceSuffix(path.value(),
-                                                   &trimmed_path_value)) {
-      i = find_data(base::FilePath(trimmed_path_value));
-    }
-  }
-  if (i == data_.end())
+  const Data::HashInfo* hash_info = data_.GetItem(relative_path);
+  if (!hash_info)
     return false;
 
-  const HashInfo& info = i->second;
-  *block_size = info.first;
-  *hashes = info.second;
+  *block_size = hash_info->block_size;
+  *hashes = hash_info->hashes;
   return true;
 }
 
@@ -222,10 +228,10 @@
     return false;
 
   base::Value file_list(base::Value::Type::LIST);
-  for (const auto& resource_info : data_) {
-    const base::FilePath& relative_path = resource_info.first;
-    int block_size = resource_info.second.first;
-    const std::vector<std::string>& hashes = resource_info.second.second;
+  for (const auto& resource_info : data_.items()) {
+    const Data::HashInfo& hash_info = resource_info.second;
+    int block_size = hash_info.block_size;
+    const std::vector<std::string>& hashes = hash_info.hashes;
 
     base::Value::ListStorage block_hashes;
     block_hashes.reserve(hashes.size());
@@ -236,9 +242,8 @@
     }
 
     base::Value dict(base::Value::Type::DICTIONARY);
-    dict.SetStringKey(
-        computed_hashes::kPathKey,
-        relative_path.NormalizePathSeparatorsTo('/').AsUTF8Unsafe());
+    dict.SetStringKey(computed_hashes::kPathKey,
+                      hash_info.relative_unix_path.AsUTF8Unsafe());
     dict.SetIntKey(computed_hashes::kBlockSizeKey, block_size);
     dict.SetKey(computed_hashes::kBlockHashesKey,
                 base::Value(std::move(block_hashes)));
@@ -298,7 +303,6 @@
 base::Optional<std::vector<std::string>>
 ComputedHashes::ComputeAndCheckResourceHash(
     const base::FilePath& full_path,
-    const base::FilePath& relative_unix_path,
     int block_size) {
   std::string contents;
   if (!base::ReadFileToString(full_path, &contents)) {
diff --git a/extensions/browser/computed_hashes.h b/extensions/browser/computed_hashes.h
index 950f3d0..7e4e7ca 100644
--- a/extensions/browser/computed_hashes.h
+++ b/extensions/browser/computed_hashes.h
@@ -13,12 +13,9 @@
 #include <vector>
 
 #include "base/callback.h"
+#include "base/files/file_path.h"
 #include "base/optional.h"
 
-namespace base {
-class FilePath;
-}
-
 namespace extensions {
 
 using IsCancelledCallback = base::RepeatingCallback<bool(void)>;
@@ -29,8 +26,60 @@
 // computed over the files inside an extension.
 class ComputedHashes {
  public:
-  using HashInfo = std::pair<int, std::vector<std::string>>;
-  using Data = std::map<base::FilePath, HashInfo>;
+  // Hashes data for relative paths.
+  // System specific path canonicalization is taken care of inside this class.
+  class Data {
+   public:
+    struct HashInfo {
+      int block_size;
+      std::vector<std::string> hashes;
+      // The relative unix style path.
+      // Note that we use canonicalized paths as keys to HashInfo's container
+      // |items_|.
+      //
+      // TODO(http://crbug.com/796395#c28): Consider removing this once
+      // ContentVerifier::ShouldVerifyAnyPaths works with canonicalized relative
+      // paths.
+      base::FilePath relative_unix_path;
+      HashInfo(int block_size,
+               std::vector<std::string> hashes,
+               base::FilePath relative_unix_path);
+      ~HashInfo();
+
+      HashInfo(const HashInfo&) = delete;
+      HashInfo& operator=(const HashInfo&) = delete;
+      HashInfo(HashInfo&&);
+      HashInfo& operator=(HashInfo&&);
+    };
+    using Items = std::map<base::FilePath::StringType, HashInfo>;
+
+    Data();
+    ~Data();
+
+    Data(const Data&) = delete;
+    Data& operator=(const Data&) = delete;
+    Data(Data&&);
+    Data& operator=(Data&&);
+
+    // For |relative_path|, adds hash information with |block_size| and
+    // |hashes|.
+    // Note that |relative_path| will be canonicalized.
+    void Add(const base::FilePath& relative_path,
+             int block_size,
+             std::vector<std::string> hashes);
+
+    // Removes the item that corresponds to |relative_path|.
+    void Remove(const base::FilePath& relative_path);
+
+    // Returns HashInfo* for |relative_path| or nullptr if not found.
+    const HashInfo* GetItem(const base::FilePath& relative_path) const;
+
+    const Items& items() const;
+
+   private:
+    // All items, stored by canonicalized FilePath::StringType key.
+    Items items_;
+  };
 
   explicit ComputedHashes(Data&& data);
   ComputedHashes(const ComputedHashes&) = delete;
@@ -79,7 +128,6 @@
   // added to computed_hashes.json for this resource.
   static base::Optional<std::vector<std::string>> ComputeAndCheckResourceHash(
       const base::FilePath& full_path,
-      const base::FilePath& relative_unix_path,
       int block_size);
 
   Data data_;
diff --git a/extensions/browser/computed_hashes_unittest.cc b/extensions/browser/computed_hashes_unittest.cc
index 95bab6f..02aa0ca 100644
--- a/extensions/browser/computed_hashes_unittest.cc
+++ b/extensions/browser/computed_hashes_unittest.cc
@@ -43,10 +43,8 @@
   base::FilePath computed_hashes_path =
       scoped_dir.GetPath().AppendASCII("computed_hashes.json");
   extensions::ComputedHashes::Data computed_hashes_data;
-  for (const auto& info : hash_infos) {
-    computed_hashes_data[info.path] =
-        extensions::ComputedHashes::HashInfo(info.block_size, info.hashes);
-  }
+  for (const auto& info : hash_infos)
+    computed_hashes_data.Add(info.path, info.block_size, info.hashes);
 
   if (!extensions::ComputedHashes(std::move(computed_hashes_data))
            .WriteToFile(computed_hashes_path)) {
diff --git a/extensions/browser/content_verifier.h b/extensions/browser/content_verifier.h
index 972c093..f39849f5 100644
--- a/extensions/browser/content_verifier.h
+++ b/extensions/browser/content_verifier.h
@@ -39,6 +39,25 @@
 // Used for managing overall content verification - both fetching content
 // hashes as needed, and supplying job objects to verify file contents as they
 // are read.
+//
+// Some notes about extension resource paths:
+// An extension resource path is a path relative to it's extension root
+// directory. For the purposes of content verification system, there can be
+// several transformations of the relative path:
+//   1. Relative path: Relative path as is. This is base::FilePath that simply
+//      is the relative path of the resource.
+//   2. Relative unix path: Some underlying parts of content-verification
+//      require uniform separator, we use '/' as separator so it is effectively
+//      unix style. Note that this is a reversible transformation.
+//   3. Canonicalized relative_path: Canonicalized paths are used as keys of
+//      maps within VerifiedContents and ComputedHashes. This takes care of OS
+//      specific file access issues:
+//      - windows/mac is case insensitive while accessing files.
+//      - windows ignores (.| )+ suffixes in filename while accessing a file.
+//      Canonicalization consists of normalizing the separators, lower casing
+//      the filepath in case-insensitive systems and trimming ignored suffixes
+//      if appropriate.
+//      See content_verifier_utils::CanonicalizeRelativePath() for details.
 class ContentVerifier : public base::RefCountedThreadSafe<ContentVerifier>,
                         public ExtensionRegistryObserver {
  public:
diff --git a/extensions/browser/content_verifier/content_hash.cc b/extensions/browser/content_verifier/content_hash.cc
index 45d6773..692275f 100644
--- a/extensions/browser/content_verifier/content_hash.cc
+++ b/extensions/browser/content_verifier/content_hash.cc
@@ -329,14 +329,15 @@
 
   std::set<base::FilePath> mismatched_hashes;
 
-  for (const auto& resource_info : *computed_hashes_data) {
-    const base::FilePath& relative_unix_path = resource_info.first;
-    const std::vector<std::string>& hashes = resource_info.second.second;
+  for (const auto& resource_info : computed_hashes_data->items()) {
+    const ComputedHashes::Data::HashInfo& hash_info = resource_info.second;
 
-    std::string root =
-        ComputeTreeHashRoot(hashes, block_size_ / crypto::kSHA256Length);
-    if (!verified_contents_->TreeHashRootEquals(relative_unix_path, root))
-      mismatched_hashes.insert(relative_unix_path);
+    std::string root = ComputeTreeHashRoot(hash_info.hashes,
+                                           block_size_ / crypto::kSHA256Length);
+    if (!verified_contents_->TreeHashRootEquals(hash_info.relative_unix_path,
+                                                root)) {
+      mismatched_hashes.insert(hash_info.relative_unix_path);
+    }
   }
 
   return mismatched_hashes;
@@ -365,7 +366,7 @@
       VLOG(1) << "content mismatch for " << relative_unix_path.AsUTF8Unsafe();
       // Remove hash entry to keep computed_hashes.json file clear of mismatched
       // hashes.
-      computed_hashes_data->erase(relative_unix_path);
+      computed_hashes_data->Remove(relative_unix_path);
     }
     hash_mismatch_unix_paths_ = std::move(hashes_mismatch);
   }
diff --git a/extensions/browser/content_verifier/content_hash_unittest.cc b/extensions/browser/content_verifier/content_hash_unittest.cc
index 42fbe22..9a3a708b 100644
--- a/extensions/browser/content_verifier/content_hash_unittest.cc
+++ b/extensions/browser/content_verifier/content_hash_unittest.cc
@@ -59,8 +59,7 @@
     for (const auto& resource : extension_resources_) {
       std::vector<std::string> hashes =
           ComputedHashes::GetHashesForContent(resource.contents, block_size);
-      computed_hashes_data[resource.relative_path] =
-          ComputedHashes::HashInfo(block_size, hashes);
+      computed_hashes_data.Add(resource.relative_path, block_size, hashes);
     }
 
     ASSERT_TRUE(ComputedHashes(std::move(computed_hashes_data))
diff --git a/extensions/browser/content_verifier/content_verifier_utils.cc b/extensions/browser/content_verifier/content_verifier_utils.cc
index 3e800cbb..cd1b780a 100644
--- a/extensions/browser/content_verifier/content_verifier_utils.cc
+++ b/extensions/browser/content_verifier/content_verifier_utils.cc
@@ -22,9 +22,10 @@
   return true;
 }
 
-base::FilePath::StringType CanonicalizeFilePath(const base::FilePath& path) {
+base::FilePath::StringType CanonicalizeRelativePath(
+    const base::FilePath& relative_path) {
   base::FilePath::StringType canonicalized_path =
-      path.NormalizePathSeparatorsTo('/').value();
+      relative_path.NormalizePathSeparatorsTo('/').value();
   if (!IsFileAccessCaseSensitive())
     canonicalized_path = base::ToLowerASCII(canonicalized_path);
   if (IsDotSpaceFilenameSuffixIgnored())
diff --git a/extensions/browser/content_verifier/content_verifier_utils.h b/extensions/browser/content_verifier/content_verifier_utils.h
index c97c1bd..1114fbc5 100644
--- a/extensions/browser/content_verifier/content_verifier_utils.h
+++ b/extensions/browser/content_verifier/content_verifier_utils.h
@@ -37,9 +37,10 @@
 #endif
 }
 
-// Returns platform specific canonicalized version of |path| for content
-// verification system.
-base::FilePath::StringType CanonicalizeFilePath(const base::FilePath& path);
+// Returns platform specific canonicalized version of |relative_path| for
+// content verification system.
+base::FilePath::StringType CanonicalizeRelativePath(
+    const base::FilePath& relative_path);
 
 }  // namespace content_verifier_utils
 }  // namespace extensions
diff --git a/extensions/browser/content_verify_job_unittest.cc b/extensions/browser/content_verify_job_unittest.cc
index c667340..eb3c653 100644
--- a/extensions/browser/content_verify_job_unittest.cc
+++ b/extensions/browser/content_verify_job_unittest.cc
@@ -76,8 +76,7 @@
   for (const auto& resource : contents) {
     std::vector<std::string> hashes =
         ComputedHashes::GetHashesForContent(resource.second, block_size);
-    computed_hashes_data[resource.first] =
-        ComputedHashes::HashInfo(block_size, hashes);
+    computed_hashes_data.Add(resource.first, block_size, std::move(hashes));
   }
 
   base::CreateDirectory(extension_root.Append(kMetadataFolder));
@@ -365,8 +364,8 @@
   const std::string kFakeContents = "fake contents";
   std::vector<std::string> hashes =
       ComputedHashes::GetHashesForContent(kFakeContents, block_size);
-  incorrect_computed_hashes_data[resource_path] =
-      ComputedHashes::HashInfo(block_size, hashes);
+  incorrect_computed_hashes_data.Add(resource_path, block_size,
+                                     std::move(hashes));
 
   ASSERT_TRUE(
       ComputedHashes(std::move(incorrect_computed_hashes_data))
diff --git a/extensions/browser/url_loader_factory_manager.cc b/extensions/browser/url_loader_factory_manager.cc
index adf43375..ed4852e 100644
--- a/extensions/browser/url_loader_factory_manager.cc
+++ b/extensions/browser/url_loader_factory_manager.cc
@@ -44,6 +44,11 @@
 
 namespace {
 
+bool ShouldAllowlistAlsoApplyToOorCors() {
+  return base::FeatureList::IsEnabled(
+      extensions_features::kCorbAllowlistAlsoAppliesToOorCors);
+}
+
 enum class FactoryUser {
   kContentScript,
   kExtensionProcess,
@@ -52,14 +57,14 @@
 // The allowlist contains HashedExtensionId of extensions discovered via
 // Extensions.CrossOriginFetchFromContentScript2 Rappor data.  When the data was
 // gathered, these extensions relied on making cross-origin requests from
-// content scripts (which requires relaxing CORB).  Going forward, these
-// extensions should migrate to making those requests from elsewhere (e.g. from
-// a background page, or in the future from extension service workers) at which
-// point they can be removed from the allowlist.
+// content scripts (which requires relaxing CORB and CORS).  Going forward,
+// these extensions should migrate to making those requests from elsewhere (e.g.
+// from a background page, or in the future from extension service workers) at
+// which point they can be removed from the allowlist.
 //
 // Migration plan for extension developers is described at
 // https://chromium.org/Home/chromium-security/extension-content-script-fetches
-const char* kHardcodedPartOfCorbAllowlist[] = {
+const char* kHardcodedPartOfAllowlist[] = {
     "039F93DD1DF836F1D4E2084C1BEFDB46A854A9D1",
     "03E5D80A49C309F7B55ED6BD2B0EDEB38021ED4E",
     "072D729E856B1F2C9894AEEC3A5DF65E519D6BEE",
@@ -251,8 +256,8 @@
   }
 
   // Append extensions from the hardcoded allowlist.
-  allowlist.reserve(base::size(kHardcodedPartOfCorbAllowlist));
-  for (const char* hash : kHardcodedPartOfCorbAllowlist) {
+  allowlist.reserve(base::size(kHardcodedPartOfAllowlist));
+  for (const char* hash : kHardcodedPartOfAllowlist) {
     DCHECK(IsValidHashedExtensionId(hash));  // It also validates the length.
     allowlist.push_back(std::string(hash, kHashedExtensionIdLength));
   }
@@ -261,7 +266,7 @@
 }
 
 // Returns a set of HashedExtensionId of extensions that depend on relaxed CORB
-// behavior in their content scripts.
+// or CORS behavior in their content scripts.
 base::flat_set<std::string>& GetExtensionsAllowlist() {
   static base::NoDestructor<base::flat_set<std::string>> s_allowlist([] {
     base::flat_set<std::string> result(CreateExtensionAllowlist());
@@ -271,14 +276,14 @@
   return *s_allowlist;
 }
 
-bool DoContentScriptsDependOnRelaxedCorb(const Extension& extension) {
+bool DoContentScriptsDependOnRelaxedCorbOrCors(const Extension& extension) {
   // Content scripts injected by Chrome Apps (e.g. into <webview> tag) need to
   // run with relaxed CORB.
   if (extension.is_platform_app())
     return true;
 
-  // Content scripts in the current version of extensions might depend on
-  // relaxed CORB.
+  // Content scripts in manifest v2 might be allowlisted to depend on relaxed
+  // CORB and/or CORS.
   if (extension.manifest_version() <= 2) {
     const std::string& hash = extension.hashed_id().value();
     DCHECK(IsValidHashedExtensionId(hash));
@@ -289,44 +294,86 @@
   return false;
 }
 
-bool DoExtensionPermissionsCoverCorsOrCorbRelatedOrigins(
-    const Extension& extension) {
-  // TODO(lukasza): https://crbug.com/1016904: Return false if the |extension|
-  // doesn't need a special URLLoaderFactory based on |extension| permissions.
-  // For now we conservatively assume that all extensions need relaxed CORS/CORB
+bool DoExtensionPermissionsCoverHttpOrHttpsOrigins(const Extension& extension) {
+  // TODO(lukasza): https://crbug.com/1016904: Return false if the |extension|'s
+  // permissions do not actually cover http or https origins.  For now we
+  // conservatively return true so that *all* extensions get relaxed CORS/CORB
   // treatment.
   return true;
 }
 
-bool IsSpecialURLLoaderFactoryRequired(const Extension& extension,
-                                       FactoryUser factory_user) {
+// Returns whether the default URLLoaderFactoryParams::is_corb_enabled should be
+// overridden and changed to false.
+bool ShouldDisableCorb(const Extension& extension, FactoryUser factory_user) {
+  if (!DoExtensionPermissionsCoverHttpOrHttpsOrigins(extension))
+    return false;
+
   switch (factory_user) {
     case FactoryUser::kContentScript:
-      return DoContentScriptsDependOnRelaxedCorb(extension) &&
-             DoExtensionPermissionsCoverCorsOrCorbRelatedOrigins(extension);
+      return DoContentScriptsDependOnRelaxedCorbOrCors(extension);
     case FactoryUser::kExtensionProcess:
-      return DoExtensionPermissionsCoverCorsOrCorbRelatedOrigins(extension);
+      return true;
   }
 }
 
+// Returns whether URLLoaderFactoryParams::ignore_isolated_world_origin should
+// be overridden and changed to false.
+bool ShouldInspectIsolatedWorldOrigin(const Extension& extension,
+                                      FactoryUser factory_user) {
+  if (!DoExtensionPermissionsCoverHttpOrHttpsOrigins(extension))
+    return false;
+
+  switch (factory_user) {
+    case FactoryUser::kContentScript:
+      // If |extensions_features::kCorbAllowlistAlsoAppliesToOorCors| is
+      // disabled, then go back to the legacy CORS behavior for all extensions.
+      if (!ShouldAllowlistAlsoApplyToOorCors())
+        return true;
+
+      // Otherwise, make an |extension|-specific decision.
+      return DoContentScriptsDependOnRelaxedCorbOrCors(extension);
+    case FactoryUser::kExtensionProcess:
+      return false;
+  }
+}
+
+bool ShouldCreateSeparateFactoryForContentScripts(const Extension& extension) {
+  return ShouldDisableCorb(extension, FactoryUser::kContentScript) ||
+         ShouldInspectIsolatedWorldOrigin(extension,
+                                          FactoryUser::kContentScript);
+}
+
 void OverrideFactoryParams(const Extension& extension,
                            FactoryUser factory_user,
                            network::mojom::URLLoaderFactoryParams* params) {
-  // Setup factory bound allow list that overwrites per-profile common list
-  // to allow tab specific permissions only for this newly created factory.
-  params->factory_bound_access_patterns =
-      network::mojom::CorsOriginAccessPatterns::New();
-  params->factory_bound_access_patterns->source_origin =
-      url::Origin::Create(extension.url());
-  params->factory_bound_access_patterns->allow_patterns =
-      CreateCorsOriginAccessAllowList(
-          extension,
-          PermissionsData::EffectiveHostPermissionsMode::kIncludeTabSpecific);
+  if (ShouldDisableCorb(extension, factory_user)) {
+    // TODO(lukasza): https://crbug.com/1016904: Use more granular CORB
+    // enforcement based on the specific |extension|'s permissions reflected
+    // in the |factory_bound_access_patterns| above.
+    params->is_corb_enabled = false;
 
-  // TODO(lukasza): https://crbug.com/1016904: Use more granular CORB
-  // enforcement based on the specific |extension|'s permissions.
-  params->is_corb_enabled = false;
+    // Setup factory bound allow list that overwrites per-profile common list to
+    // allow tab specific permissions only for this newly created factory.
+    //
+    // TODO(lukasza): Setting |factory_bound_access_patterns| together with
+    // |is_corb_enabled| seems accidental.
+    params->factory_bound_access_patterns =
+        network::mojom::CorsOriginAccessPatterns::New();
+    params->factory_bound_access_patterns->source_origin =
+        url::Origin::Create(extension.url());
+    params->factory_bound_access_patterns->allow_patterns =
+        CreateCorsOriginAccessAllowList(
+            extension,
+            PermissionsData::EffectiveHostPermissionsMode::kIncludeTabSpecific);
+    params->factory_bound_access_patterns->block_patterns =
+        CreateCorsOriginAccessBlockList(extension);
+  }
 
+  if (ShouldInspectIsolatedWorldOrigin(extension, factory_user))
+    params->ignore_isolated_world_origin = false;
+
+  // TODO(lukasza): Do not override |unsafe_non_webby_initiator| unless
+  // DoExtensionPermissionsCoverHttpOrHttpsOrigins(extension).
   if (factory_user == FactoryUser::kExtensionProcess)
     params->unsafe_non_webby_initiator = true;
 }
@@ -456,8 +503,7 @@
     if (!DoContentScriptsMatchNavigatingFrame(extension, frame, url))
       continue;
 
-    if (!IsSpecialURLLoaderFactoryRequired(extension,
-                                           FactoryUser::kContentScript))
+    if (!ShouldCreateSeparateFactoryForContentScripts(extension))
       continue;
 
     initiators_requiring_separate_factory.push_back(
@@ -489,8 +535,7 @@
       registry->enabled_extensions().GetByID(host_id.id());
   DCHECK(extension);  // Guaranteed by the caller - see the doc comment.
 
-  if (!IsSpecialURLLoaderFactoryRequired(*extension,
-                                         FactoryUser::kContentScript))
+  if (!ShouldCreateSeparateFactoryForContentScripts(*extension))
     return;
 
   // When WillExecuteCode runs, the frame already received the initial
@@ -535,13 +580,10 @@
     return;
   }
 
-  // Don't change |factory_params| unless required.
+  // Identify and set |factory_params| that need to be overridden.
   FactoryUser factory_user = is_for_isolated_world
                                  ? FactoryUser::kContentScript
                                  : FactoryUser::kExtensionProcess;
-  if (!IsSpecialURLLoaderFactoryRequired(*extension, factory_user))
-    return;
-
   OverrideFactoryParams(*extension, factory_user, factory_params);
 }
 
diff --git a/extensions/browser/verified_contents.cc b/extensions/browser/verified_contents.cc
index a80acc1..73ccd07 100644
--- a/extensions/browser/verified_contents.cc
+++ b/extensions/browser/verified_contents.cc
@@ -172,7 +172,7 @@
       }
 
       base::FilePath::StringType canonicalized_path =
-          content_verifier_utils::CanonicalizeFilePath(
+          content_verifier_utils::CanonicalizeRelativePath(
               base::FilePath::FromUTF8Unsafe(*file_path_string));
       auto i = verified_contents->root_hashes_.insert(
           std::make_pair(canonicalized_path, std::string()));
@@ -189,13 +189,14 @@
     const base::FilePath& relative_path) const {
   return base::Contains(
       root_hashes_,
-      content_verifier_utils::CanonicalizeFilePath(relative_path));
+      content_verifier_utils::CanonicalizeRelativePath(relative_path));
 }
 
 bool VerifiedContents::TreeHashRootEquals(const base::FilePath& relative_path,
                                           const std::string& expected) const {
   return TreeHashRootEqualsImpl(
-      content_verifier_utils::CanonicalizeFilePath(relative_path), expected);
+      content_verifier_utils::CanonicalizeRelativePath(relative_path),
+      expected);
 }
 
 // We're loosely following the "JSON Web Signature" draft spec for signing
diff --git a/extensions/common/extension_features.cc b/extensions/common/extension_features.cc
index 8c5d90c..1cffd0e 100644
--- a/extensions/common/extension_features.cc
+++ b/extensions/common/extension_features.cc
@@ -28,6 +28,15 @@
 const char kPrivacyMessage[] = "1";
 const char kNeutralMessage[] = "2";
 
+// Controls whether the CORB allowlist [1] is also applied to OOR-CORS (e.g.
+// whether non-allowlisted content scripts can bypass CORS in OOR-CORS mode).
+// See also: https://crbug.com/920638
+//
+// [1]
+// https://www.chromium.org/Home/chromium-security/extension-content-script-fetches
+const base::Feature kCorbAllowlistAlsoAppliesToOorCors{
+    "CorbAllowlistAlsoAppliesToOorCors", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Forces requests to go through WebRequestProxyingURLLoaderFactory.
 const base::Feature kForceWebRequestProxyForTest{
     "ForceWebRequestProxyForTest", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/extensions/common/extension_features.h b/extensions/common/extension_features.h
index b3983c0..4be1737f 100644
--- a/extensions/common/extension_features.h
+++ b/extensions/common/extension_features.h
@@ -18,6 +18,7 @@
 extern const char kPrivacyMessage[];
 extern const char kNeutralMessage[];
 
+extern const base::Feature kCorbAllowlistAlsoAppliesToOorCors;
 extern const base::Feature kForceWebRequestProxyForTest;
 
 }  // namespace extensions_features
diff --git a/fuchsia/engine/context_provider_impl.cc b/fuchsia/engine/context_provider_impl.cc
index 402d9d6..31799b8 100644
--- a/fuchsia/engine/context_provider_impl.cc
+++ b/fuchsia/engine/context_provider_impl.cc
@@ -127,6 +127,23 @@
   return std::move(*config);
 }
 
+void AppendFeature(base::StringPiece features_flag,
+                   base::StringPiece feature_string,
+                   base::CommandLine* command_line) {
+  if (!command_line->HasSwitch(features_flag)) {
+    command_line->AppendSwitchNative(features_flag.as_string(),
+                                     feature_string.as_string());
+    return;
+  }
+
+  std::string new_feature_string =
+      command_line->GetSwitchValueASCII(features_flag);
+  new_feature_string.append(",").append(feature_string.as_string());
+  command_line->RemoveSwitch(features_flag);
+  command_line->AppendSwitchNative(features_flag.as_string(),
+                                   new_feature_string);
+}
+
 // Returns false if the config is present but has invalid contents.
 bool MaybeAddCommandLineArgsFromConfig(const base::Value& config,
                                        base::CommandLine* command_line) {
@@ -135,6 +152,7 @@
     return true;
 
   static const base::StringPiece kAllowedArgs[] = {
+      switches::kDisableFeatures,
       switches::kDisableGpuWatchdog,
       switches::kEnableFeatures,
       switches::kEnableFuchsiaAudioConsumer,
@@ -156,6 +174,8 @@
       LOG(ERROR) << "Config command-line arg must be a string: " << arg.first;
       return false;
     }
+
+    DCHECK(!command_line->HasSwitch(arg.first));
     command_line->AppendSwitchNative(arg.first, arg.second.GetString());
 
     // TODO(https://crbug.com/1023012): enable-low-end-device-mode currently
@@ -260,6 +280,13 @@
   base::CommandLine launch_command = *base::CommandLine::ForCurrentProcess();
   std::vector<zx::channel> devtools_listener_channels;
 
+  base::Value web_engine_config =
+      config_for_test_.is_none() ? LoadConfig() : std::move(config_for_test_);
+  if (!MaybeAddCommandLineArgsFromConfig(web_engine_config, &launch_command)) {
+    context_request.Close(ZX_ERR_INTERNAL);
+    return;
+  }
+
   if (params.has_remote_debugging_port()) {
     launch_command.AppendSwitchNative(
         switches::kRemoteDebuggingPort,
@@ -332,8 +359,8 @@
     launch_command.AppendSwitch(switches::kUseVulkan);
     const std::vector<base::StringPiece> enabled_features = {
         features::kUseSkiaRenderer.name, features::kVulkan.name};
-    launch_command.AppendSwitchASCII(switches::kEnableFeatures,
-                                     base::JoinString(enabled_features, ","));
+    AppendFeature(switches::kEnableFeatures,
+                  base::JoinString(enabled_features, ","), &launch_command);
 
     // SkiaRenderer requires out-of-process rasterization be enabled.
     launch_command.AppendSwitch(switches::kEnableOopRasterization);
@@ -350,9 +377,6 @@
     launch_command.AppendSwitch(switches::kDisableSoftwareRasterizer);
   }
 
-  base::Value web_engine_config =
-      config_for_test_.is_none() ? LoadConfig() : std::move(config_for_test_);
-
   bool allow_protected_graphics =
       web_engine_config.FindBoolPath("allow-protected-graphics")
           .value_or(false);
@@ -411,11 +435,6 @@
     launch_command.AppendSwitch(switches::kDisableSoftwareVideoDecoders);
   }
 
-  if (!MaybeAddCommandLineArgsFromConfig(web_engine_config, &launch_command)) {
-    context_request.Close(ZX_ERR_INTERNAL);
-    return;
-  }
-
   // Validate embedder-supplied product, and optional version, and pass it to
   // the Context to include in the UserAgent.
   if (params.has_user_agent_product()) {
@@ -463,8 +482,8 @@
 
   // TODO(crbug.com/1039788): Re-enable OutOfBlinkCors when custom HTTP header
   // preflight validation errors are fixed.
-  launch_command.AppendSwitchASCII("disable-features",
-                                   network::features::kOutOfBlinkCors.name);
+  AppendFeature(switches::kDisableFeatures,
+                network::features::kOutOfBlinkCors.name, &launch_command);
 
   if (launch_for_test_)
     launch_for_test_.Run(launch_command, launch_options);
diff --git a/gpu/ipc/service/gpu_init.cc b/gpu/ipc/service/gpu_init.cc
index 04883fc..433a6bd7 100644
--- a/gpu/ipc/service/gpu_init.cc
+++ b/gpu/ipc/service/gpu_init.cc
@@ -221,11 +221,6 @@
   delayed_watchdog_enable = true;
 #endif
 
-  // PreSandbox is mainly for resource handling and not related to the GPU
-  // driver, it doesn't need the GPU watchdog. The loadLibrary may take long
-  // time that killing and restarting the GPU process will not help.
-  sandbox_helper_->PreSandboxStartup();
-
   // Start the GPU watchdog only after anything that is expected to be time
   // consuming has completed, otherwise the process is liable to be aborted.
   if (enable_watchdog && !delayed_watchdog_enable) {
@@ -308,6 +303,14 @@
       return false;
     }
 
+    // The ContentSandboxHelper is currently the only one implementation of
+    // gpu::GpuSandboxHelper and it has no dependency. Except on Linux where
+    // VaapiWrapper checks the GL implementation to determine which display
+    // to use. So call PreSandboxStartup after GL initialization. But make
+    // sure the watchdog is still in pause as loadLibrary may take a long time
+    // and restarting the GPU process will not help.
+    sandbox_helper_->PreSandboxStartup();
+
     if (watchdog_thread_)
       watchdog_thread_->ResumeWatchdog();
     if (gl::GetGLImplementation() != gl::kGLImplementationDisabled) {
diff --git a/infra/config/generated/luci-scheduler.cfg b/infra/config/generated/luci-scheduler.cfg
index 0908d19c..42e0ecd 100644
--- a/infra/config/generated/luci-scheduler.cfg
+++ b/infra/config/generated/luci-scheduler.cfg
@@ -362,7 +362,6 @@
   triggers: "linux-blink-heap-verification"
   triggers: "linux-chromeos-dbg"
   triggers: "linux-chromium-tests-staging-builder"
-  triggers: "linux-code-coverage"
   triggers: "linux-archive-dbg"
   triggers: "linux-gcc-rel"
   triggers: "linux-ozone-rel"
@@ -2555,16 +2554,6 @@
 }
 
 job {
-  id: "linux-code-coverage"
-  acl_sets: "default"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci"
-    builder: "linux-code-coverage"
-  }
-}
-
-job {
   id: "linux-archive-dbg"
   acl_sets: "default"
   buildbucket: {
diff --git a/infra/config/luci-scheduler.cfg b/infra/config/luci-scheduler.cfg
index 0908d19c..42e0ecd 100644
--- a/infra/config/luci-scheduler.cfg
+++ b/infra/config/luci-scheduler.cfg
@@ -362,7 +362,6 @@
   triggers: "linux-blink-heap-verification"
   triggers: "linux-chromeos-dbg"
   triggers: "linux-chromium-tests-staging-builder"
-  triggers: "linux-code-coverage"
   triggers: "linux-archive-dbg"
   triggers: "linux-gcc-rel"
   triggers: "linux-ozone-rel"
@@ -2555,16 +2554,6 @@
 }
 
 job {
-  id: "linux-code-coverage"
-  acl_sets: "default"
-  buildbucket: {
-    server: "cr-buildbucket.appspot.com"
-    bucket: "luci.chromium.ci"
-    builder: "linux-code-coverage"
-  }
-}
-
-job {
   id: "linux-archive-dbg"
   acl_sets: "default"
   buildbucket: {
diff --git a/ios/chrome/app/BUILD.gn b/ios/chrome/app/BUILD.gn
index e73c4b6..7e479f9 100644
--- a/ios/chrome/app/BUILD.gn
+++ b/ios/chrome/app/BUILD.gn
@@ -186,6 +186,8 @@
     "//ios/chrome/browser/content_settings",
     "//ios/chrome/browser/crash_report",
     "//ios/chrome/browser/crash_report:crash_report_internal",
+    "//ios/chrome/browser/crash_report/breadcrumbs",
+    "//ios/chrome/browser/crash_report/breadcrumbs:feature_flags",
     "//ios/chrome/browser/download",
     "//ios/chrome/browser/external_files",
     "//ios/chrome/browser/favicon",
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index f08bf7c..5a63d9f 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -72,8 +72,12 @@
 #include "ios/chrome/browser/chrome_url_constants.h"
 #import "ios/chrome/browser/chrome_url_util.h"
 #include "ios/chrome/browser/content_settings/host_content_settings_map_factory.h"
+#include "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_keyed_service.h"
+#include "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_keyed_service_factory.h"
+#include "ios/chrome/browser/crash_report/breadcrumbs/features.h"
 #include "ios/chrome/browser/crash_report/breakpad_helper.h"
 #include "ios/chrome/browser/crash_report/crash_loop_detection_util.h"
+#include "ios/chrome/browser/crash_report/crash_report_helper.h"
 #include "ios/chrome/browser/download/download_directory_util.h"
 #import "ios/chrome/browser/external_files/external_file_remover_factory.h"
 #import "ios/chrome/browser/external_files/external_file_remover_impl.h"
@@ -586,6 +590,13 @@
   // Initialize and set the main browser state.
   [self initializeBrowserState:chromeBrowserState];
   self.mainBrowserState = chromeBrowserState;
+
+  if (base::FeatureList::IsEnabled(kLogBreadcrumbs)) {
+    breakpad::MonitorBreadcrumbManagerService(
+        BreadcrumbManagerKeyedServiceFactory::GetForBrowserState(
+            self.mainBrowserState));
+  }
+
   [self.browserViewWrangler shutdown];
   self.browserViewWrangler = [[BrowserViewWrangler alloc]
              initWithBrowserState:self.mainBrowserState
@@ -786,6 +797,17 @@
   [_spotlightManager shutdown];
   _spotlightManager = nil;
 
+  if (base::FeatureList::IsEnabled(kLogBreadcrumbs)) {
+    if (self.mainBrowserState->HasOffTheRecordChromeBrowserState()) {
+      breakpad::StopMonitoringBreadcrumbManagerService(
+          BreadcrumbManagerKeyedServiceFactory::GetForBrowserState(
+              self.mainBrowserState->GetOffTheRecordChromeBrowserState()));
+    }
+    breakpad::StopMonitoringBreadcrumbManagerService(
+        BreadcrumbManagerKeyedServiceFactory::GetForBrowserState(
+            self.mainBrowserState));
+  }
+
   // Invariant: The UI is stopped before the model is shutdown.
   DCHECK(!_mainCoordinator);
   [self.browserViewWrangler shutdown];
diff --git a/ios/chrome/browser/BUILD.gn b/ios/chrome/browser/BUILD.gn
index 39b7478..21d4f0b 100644
--- a/ios/chrome/browser/BUILD.gn
+++ b/ios/chrome/browser/BUILD.gn
@@ -218,6 +218,9 @@
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/browser_state:browser_state_impl",
     "//ios/chrome/browser/component_updater",
+    "//ios/chrome/browser/crash_report/breadcrumbs",
+    "//ios/chrome/browser/crash_report/breadcrumbs:application_breadcrumbs_logger",
+    "//ios/chrome/browser/crash_report/breadcrumbs:feature_flags",
     "//ios/chrome/browser/first_run",
     "//ios/chrome/browser/flags",
     "//ios/chrome/browser/gcm",
diff --git a/ios/chrome/browser/application_context_impl.cc b/ios/chrome/browser/application_context_impl.cc
index 8498eb7..377f319 100644
--- a/ios/chrome/browser/application_context_impl.cc
+++ b/ios/chrome/browser/application_context_impl.cc
@@ -9,6 +9,7 @@
 
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/feature_list.h"
 #include "base/files/file_path.h"
 #include "base/logging.h"
 #include "base/macros.h"
@@ -42,6 +43,9 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state_manager_impl.h"
 #include "ios/chrome/browser/chrome_paths.h"
 #include "ios/chrome/browser/component_updater/ios_component_updater_configurator.h"
+#include "ios/chrome/browser/crash_report/breadcrumbs/application_breadcrumbs_logger.h"
+#include "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager.h"
+#include "ios/chrome/browser/crash_report/breadcrumbs/features.h"
 #include "ios/chrome/browser/gcm/ios_chrome_gcm_profile_service_factory.h"
 #include "ios/chrome/browser/history/history_service_factory.h"
 #include "ios/chrome/browser/ios_chrome_io_thread.h"
@@ -182,6 +186,13 @@
   ukm::UkmService* ukm_service = GetMetricsServicesManager()->GetUkmService();
   if (ukm_service)
     ukm_service->OnAppEnterForeground();
+
+  if (base::FeatureList::IsEnabled(kLogBreadcrumbs) && !breadcrumb_manager_) {
+    breadcrumb_manager_ = std::make_unique<BreadcrumbManager>();
+    application_breadcrumbs_logger_ =
+        std::make_unique<ApplicationBreadcrumbsLogger>(
+            breadcrumb_manager_.get());
+  }
 }
 
 void ApplicationContextImpl::OnAppEnterBackground() {
diff --git a/ios/chrome/browser/application_context_impl.h b/ios/chrome/browser/application_context_impl.h
index 5a7a49f..e0a53cd 100644
--- a/ios/chrome/browser/application_context_impl.h
+++ b/ios/chrome/browser/application_context_impl.h
@@ -18,6 +18,9 @@
 class SequencedTaskRunner;
 }
 
+class BreadcrumbManager;
+class ApplicationBreadcrumbsLogger;
+
 namespace network {
 class NetworkChangeManager;
 }
@@ -80,6 +83,14 @@
   void CreateGCMDriver();
 
   base::ThreadChecker thread_checker_;
+
+  // Breadcrumb manager used to store application wide breadcrumb events. Will
+  // be null if breadcrumbs feature is not enabled.
+  std::unique_ptr<BreadcrumbManager> breadcrumb_manager_;
+  // Logger which observers and logs application wide events to
+  // |breadcrumb_manager_|. Will be null if breadcrumbs feature is not enabled.
+  std::unique_ptr<ApplicationBreadcrumbsLogger> application_breadcrumbs_logger_;
+
   std::unique_ptr<PrefService> local_state_;
   std::unique_ptr<net_log::NetExportFileWriter> net_export_file_writer_;
   std::unique_ptr<network_time::NetworkTimeTracker> network_time_tracker_;
diff --git a/ios/chrome/browser/crash_report/breadcrumbs/BUILD.gn b/ios/chrome/browser/crash_report/breadcrumbs/BUILD.gn
index 11f8845..0df897af 100644
--- a/ios/chrome/browser/crash_report/breadcrumbs/BUILD.gn
+++ b/ios/chrome/browser/crash_report/breadcrumbs/BUILD.gn
@@ -49,10 +49,27 @@
   configs += [ "//build/config/compiler:enable_arc" ]
 }
 
+source_set("application_breadcrumbs_logger") {
+  sources = [
+    "application_breadcrumbs_logger.h",
+    "application_breadcrumbs_logger.mm",
+  ]
+
+  configs += [ "//build/config/compiler:enable_arc" ]
+
+  deps = [
+    ":breadcrumbs",
+    "//base",
+    "//ios/chrome/browser/crash_report:crash_report_internal",
+    "//ios/chrome/browser/crash_report/breadcrumbs",
+  ]
+}
+
 source_set("unit_tests") {
   configs += [ "//build/config/compiler:enable_arc" ]
   testonly = true
   deps = [
+    ":application_breadcrumbs_logger",
     ":breadcrumbs",
     "//base/test:test_support",
     "//ios/chrome/browser/browser_state:test_support",
@@ -68,6 +85,7 @@
   ]
 
   sources = [
+    "application_breadcrumbs_logger_unittest.mm",
     "breadcrumb_manager_browser_agent_unittest.mm",
     "breadcrumb_manager_keyed_service_unittest.mm",
     "breadcrumb_manager_observer_bridge_unittest.mm",
diff --git a/ios/chrome/browser/crash_report/breadcrumbs/application_breadcrumbs_logger.h b/ios/chrome/browser/crash_report/breadcrumbs/application_breadcrumbs_logger.h
new file mode 100644
index 0000000..0864daf7
--- /dev/null
+++ b/ios/chrome/browser/crash_report/breadcrumbs/application_breadcrumbs_logger.h
@@ -0,0 +1,42 @@
+// 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 IOS_CHROME_BROWSER_CRASH_REPORT_BREADCRUMBS_APPLICATION_BREADCRUMBS_LOGGER_H_
+#define IOS_CHROME_BROWSER_CRASH_REPORT_BREADCRUMBS_APPLICATION_BREADCRUMBS_LOGGER_H_
+
+#include <memory>
+
+#include "base/memory/memory_pressure_listener.h"
+#include "base/metrics/user_metrics.h"
+
+class BreadcrumbManager;
+
+// Listens for and logs application wide breadcrumb events to the
+// BreadcrumbManager passed in the constructor.
+class ApplicationBreadcrumbsLogger {
+ public:
+  explicit ApplicationBreadcrumbsLogger(BreadcrumbManager* breadcrumb_manager);
+  ~ApplicationBreadcrumbsLogger();
+
+ private:
+  ApplicationBreadcrumbsLogger(const ApplicationBreadcrumbsLogger&) = delete;
+
+  // Callback which processes and logs the user action |action| to
+  // |breadcrumb_manager_|.
+  void OnUserAction(const std::string& action);
+
+  // Callback which processes and logs memory pressure warnings to
+  // |breadcrumb_manager_|.
+  void OnMemoryPressure(
+      base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level);
+
+  // The BreadcrumbManager to log events.
+  BreadcrumbManager* breadcrumb_manager_;
+  // The callback invoked whenever a user action is registered.
+  base::ActionCallback user_action_callback_;
+  // A memory pressure listener which observes memory pressure events.
+  std::unique_ptr<base::MemoryPressureListener> memory_pressure_listener_;
+};
+
+#endif  // IOS_CHROME_BROWSER_CRASH_REPORT_BREADCRUMBS_APPLICATION_BREADCRUMBS_LOGGER_H_
diff --git a/ios/chrome/browser/crash_report/breadcrumbs/application_breadcrumbs_logger.mm b/ios/chrome/browser/crash_report/breadcrumbs/application_breadcrumbs_logger.mm
new file mode 100644
index 0000000..ed9c2e70
--- /dev/null
+++ b/ios/chrome/browser/crash_report/breadcrumbs/application_breadcrumbs_logger.mm
@@ -0,0 +1,63 @@
+// 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 "ios/chrome/browser/crash_report/breadcrumbs/application_breadcrumbs_logger.h"
+
+#include "base/bind.h"
+#include "base/strings/stringprintf.h"
+#include "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager.h"
+#import "ios/chrome/browser/crash_report/crash_report_helper.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+ApplicationBreadcrumbsLogger::ApplicationBreadcrumbsLogger(
+    BreadcrumbManager* breadcrumb_manager)
+    : breadcrumb_manager_(breadcrumb_manager),
+      user_action_callback_(
+          base::BindRepeating(&ApplicationBreadcrumbsLogger::OnUserAction,
+                              base::Unretained(this))),
+      memory_pressure_listener_(std::make_unique<base::MemoryPressureListener>(
+          base::BindRepeating(&ApplicationBreadcrumbsLogger::OnMemoryPressure,
+                              base::Unretained(this)))) {
+  base::AddActionCallback(user_action_callback_);
+  breakpad::MonitorBreadcrumbManager(breadcrumb_manager_);
+}
+
+ApplicationBreadcrumbsLogger::~ApplicationBreadcrumbsLogger() {
+  base::RemoveActionCallback(user_action_callback_);
+  breakpad::StopMonitoringBreadcrumbManager(breadcrumb_manager_);
+}
+
+void ApplicationBreadcrumbsLogger::OnUserAction(const std::string& action) {
+  // Filter out unwanted actions.
+  if (action.find("InProductHelp.") == 0) {
+    // InProductHelp actions are very noisy.
+    return;
+  }
+
+  std::string event = base::StringPrintf("UserAction: %s", action.c_str());
+  breadcrumb_manager_->AddEvent(event);
+}
+
+void ApplicationBreadcrumbsLogger::OnMemoryPressure(
+    base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
+  std::string pressure_string = "";
+  switch (memory_pressure_level) {
+    case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
+      pressure_string = "None";
+      break;
+    case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
+      pressure_string = "Moderate";
+      break;
+    case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
+      pressure_string = "Critical";
+      break;
+  }
+
+  std::string event =
+      base::StringPrintf("Memory Pressure: %s", pressure_string.c_str());
+  breadcrumb_manager_->AddEvent(event);
+}
diff --git a/ios/chrome/browser/crash_report/breadcrumbs/application_breadcrumbs_logger_unittest.mm b/ios/chrome/browser/crash_report/breadcrumbs/application_breadcrumbs_logger_unittest.mm
new file mode 100644
index 0000000..cada6e7
--- /dev/null
+++ b/ios/chrome/browser/crash_report/breadcrumbs/application_breadcrumbs_logger_unittest.mm
@@ -0,0 +1,80 @@
+// 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 "ios/chrome/browser/crash_report/breadcrumbs/application_breadcrumbs_logger.h"
+
+#include "base/memory/memory_pressure_listener.h"
+#include "base/metrics/user_metrics_action.h"
+#include "base/run_loop.h"
+#include "base/test/task_environment.h"
+#import "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager.h"
+#include "testing/platform_test.h"
+
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
+namespace {
+// The particular UserActions used here are not important, but real UserAction
+// names are used to prevent a presubmit warning.
+const char kUserAction1Name[] = "MobileMenuNewTab";
+const char kUserAction2Name[] = "MobileTabClosed";
+// An "InProductHelp.*" user action.
+const char kInProductHelpUserActionName[] = "InProductHelp.Dismissed";
+}  // namespace
+
+using MemoryPressureLevel = base::MemoryPressureListener::MemoryPressureLevel;
+
+// Test fixture for testing ApplicationBreadcrumbsLogger class.
+class ApplicationBreadcrumbsLoggerTest : public PlatformTest {
+ protected:
+  ApplicationBreadcrumbsLoggerTest()
+      : logger_(std::make_unique<ApplicationBreadcrumbsLogger>(
+            &breadcrumb_manager_)) {}
+
+  base::test::TaskEnvironment task_environment_;
+  BreadcrumbManager breadcrumb_manager_;
+  std::unique_ptr<ApplicationBreadcrumbsLogger> logger_;
+};
+
+// Tests that a recorded UserAction is logged by the
+// ApplicationBreadcrumbsLogger.
+TEST_F(ApplicationBreadcrumbsLoggerTest, UserAction) {
+  base::RecordAction(base::UserMetricsAction(kUserAction1Name));
+  base::RecordAction(base::UserMetricsAction(kUserAction2Name));
+
+  std::list<std::string> events = breadcrumb_manager_.GetEvents(0);
+  ASSERT_EQ(2ul, events.size());
+  EXPECT_NE(std::string::npos, events.front().find(kUserAction1Name));
+  // Ensure UserAction events are labeled as such.
+  EXPECT_NE(std::string::npos, events.front().find("UserAction: "));
+  events.pop_front();
+  EXPECT_NE(std::string::npos, events.front().find(kUserAction2Name));
+}
+
+// Tests that "InProductHelp" UserActions are not logged by
+// ApplicationBreadcrumbsLogger as they are very noisy.
+TEST_F(ApplicationBreadcrumbsLoggerTest, SkipInProductHelpUserActions) {
+  base::RecordAction(base::UserMetricsAction(kInProductHelpUserActionName));
+
+  std::list<std::string> events = breadcrumb_manager_.GetEvents(0);
+  ASSERT_EQ(0ul, events.size());
+}
+
+// Tests that memory pressure events are logged by ApplicationBreadcrumbsLogger.
+TEST_F(ApplicationBreadcrumbsLoggerTest, MemoryPressure) {
+  base::MemoryPressureListener::SimulatePressureNotification(
+      MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_MODERATE);
+  base::MemoryPressureListener::SimulatePressureNotification(
+      MemoryPressureLevel::MEMORY_PRESSURE_LEVEL_CRITICAL);
+  base::RunLoop().RunUntilIdle();
+
+  std::list<std::string> events = breadcrumb_manager_.GetEvents(0);
+  ASSERT_EQ(2ul, events.size());
+  EXPECT_NE(std::string::npos, events.front().find("Moderate"));
+  // Ensure UserAction events are labeled as such.
+  EXPECT_NE(std::string::npos, events.front().find("Memory Pressure: "));
+  events.pop_front();
+  EXPECT_NE(std::string::npos, events.front().find("Critical"));
+}
diff --git a/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_keyed_service_factory.h b/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_keyed_service_factory.h
index 55102684..1be634d 100644
--- a/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_keyed_service_factory.h
+++ b/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_keyed_service_factory.h
@@ -7,13 +7,10 @@
 
 #include "base/no_destructor.h"
 #include "components/keyed_service/ios/browser_state_keyed_service_factory.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state_forward.h"
 
 class BreadcrumbManagerKeyedService;
 
-namespace ios {
-class ChromeBrowserState;
-}
-
 class BreadcrumbManagerKeyedServiceFactory
     : public BrowserStateKeyedServiceFactory {
  public:
diff --git a/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_persistent_storage_keyed_service_factory.h b/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_persistent_storage_keyed_service_factory.h
index 364cf7c7..e27068c6 100644
--- a/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_persistent_storage_keyed_service_factory.h
+++ b/ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_persistent_storage_keyed_service_factory.h
@@ -7,13 +7,10 @@
 
 #include "base/no_destructor.h"
 #include "components/keyed_service/ios/browser_state_keyed_service_factory.h"
+#include "ios/chrome/browser/browser_state/chrome_browser_state_forward.h"
 
 class BreadcrumbPersistentStorageKeyedService;
 
-namespace ios {
-class ChromeBrowserState;
-}
-
 class BreadcrumbPersistentStorageKeyedServiceFactory
     : public BrowserStateKeyedServiceFactory {
  public:
diff --git a/ios/chrome/browser/crash_report/crash_report_helper.h b/ios/chrome/browser/crash_report/crash_report_helper.h
index 259c8f6..524604a 100644
--- a/ios/chrome/browser/crash_report/crash_report_helper.h
+++ b/ios/chrome/browser/crash_report/crash_report_helper.h
@@ -9,6 +9,9 @@
 
 @class NSString;
 
+class BreadcrumbManager;
+class BreadcrumbManagerKeyedService;
+
 namespace web {
 class WebState;
 }  // namespace web
@@ -44,15 +47,21 @@
 // be called when the WebStateList is deactivated.
 void ClearStateForWebStateList(WebStateList* web_state_list);
 
-// Starts listening for breadcrumbs logged to |browser_state|'s
-// BreadcrumbManagerKeyedService. Collected breadcrumbs will be attached to
-// crash reports.
-void MonitorBreadcrumbsForBrowserState(ios::ChromeBrowserState* browser_state);
+// Starts listening for breadcrumbs logged to |breadcrumb_manager|. Collected
+// breadcrumbs will be attached to crash reports.
+void MonitorBreadcrumbManager(BreadcrumbManager* breadcrumb_manager);
 
-// Stops listening for breadcrumbs logged to |browser_state|'s
-// BreadcrumbManagerKeyedService.
-void StopMonitoringBreadcrumbsForBrowserState(
-    ios::ChromeBrowserState* browser_state);
+// Stops listening for breadcrumbs logged to |breadcrumb_manager|.
+void StopMonitoringBreadcrumbManager(BreadcrumbManager* breadcrumb_manager);
+
+// Starts listening for breadcrumbs logged to |breadcrumb_manager_service|.
+// Collected breadcrumbs will be attached to crash reports.
+void MonitorBreadcrumbManagerService(
+    BreadcrumbManagerKeyedService* breadcrumb_manager_service);
+
+// Stops listening for breadcrumbs logged to |breadcrumb_manager_service|.
+void StopMonitoringBreadcrumbManagerService(
+    BreadcrumbManagerKeyedService* breadcrumb_manager_service);
 
 }  // namespace breakpad
 
diff --git a/ios/chrome/browser/crash_report/crash_report_helper.mm b/ios/chrome/browser/crash_report/crash_report_helper.mm
index b78b545..0df584d 100644
--- a/ios/chrome/browser/crash_report/crash_report_helper.mm
+++ b/ios/chrome/browser/crash_report/crash_report_helper.mm
@@ -439,15 +439,26 @@
   }
 }
 
-void MonitorBreadcrumbsForBrowserState(ios::ChromeBrowserState* browser_state) {
+void MonitorBreadcrumbManager(BreadcrumbManager* breadcrumb_manager) {
   [[CrashReporterBreadcrumbObserver uniqueInstance]
-      observeBrowserState:browser_state];
+      observeBreadcrumbManager:breadcrumb_manager];
 }
 
-void StopMonitoringBreadcrumbsForBrowserState(
-    ios::ChromeBrowserState* browser_state) {
+void StopMonitoringBreadcrumbManager(BreadcrumbManager* breadcrumb_manager) {
   [[CrashReporterBreadcrumbObserver uniqueInstance]
-      stopObservingBrowserState:browser_state];
+      stopObservingBreadcrumbManager:breadcrumb_manager];
+}
+
+void MonitorBreadcrumbManagerService(
+    BreadcrumbManagerKeyedService* breadcrumb_manager_service) {
+  [[CrashReporterBreadcrumbObserver uniqueInstance]
+      observeBreadcrumbManagerService:breadcrumb_manager_service];
+}
+
+void StopMonitoringBreadcrumbManagerService(
+    BreadcrumbManagerKeyedService* breadcrumb_manager_service) {
+  [[CrashReporterBreadcrumbObserver uniqueInstance]
+      stopObservingBreadcrumbManagerService:breadcrumb_manager_service];
 }
 
 }  // namespace breakpad
diff --git a/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer.h b/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer.h
index d7a74f9d..e8cfa1fc 100644
--- a/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer.h
+++ b/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer.h
@@ -13,8 +13,8 @@
 #include "ios/chrome/browser/browser_state/chrome_browser_state_forward.h"
 #import "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_observer_bridge.h"
 
-// Combines breadcrumbs from multiple ChromeBrowserState instances and sends the
-// merged breadcrumb events to breakpad for attachment to crash reports.
+// Combines breadcrumbs from multiple BreadcrumbManagers and sends the merged
+// breadcrumb events to breakpad for attachment to crash reports.
 @interface CrashReporterBreadcrumbObserver
     : NSObject <BreadcrumbManagerObserving> {
 }
@@ -22,10 +22,19 @@
 // Creates a singleton instance.
 + (CrashReporterBreadcrumbObserver*)uniqueInstance;
 
-// Starts collecting breadcrumb events associated with |browserState|.
-- (void)observeBrowserState:(ios::ChromeBrowserState*)browserState;
-// Stops collecting breadcrumb events associated with |browserState|.
-- (void)stopObservingBrowserState:(ios::ChromeBrowserState*)browserState;
+// Starts collecting breadcrumb events logged to |breadcrumbManager|.
+- (void)observeBreadcrumbManager:(BreadcrumbManager*)breadcrumbManager;
+
+// Stops collecting breadcrumb events logged to |breadcrumbManager|.
+- (void)stopObservingBreadcrumbManager:(BreadcrumbManager*)breadcrumbManager;
+
+// Starts collecting breadcrumb events logged to |breadcrumbManagerService|.
+- (void)observeBreadcrumbManagerService:
+    (BreadcrumbManagerKeyedService*)breadcrumbManagerService;
+
+// Stops collecting breadcrumb events logged to |breadcrumbManagerService|.
+- (void)stopObservingBreadcrumbManagerService:
+    (BreadcrumbManagerKeyedService*)breadcrumbManagerService;
 
 @end
 
diff --git a/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer.mm b/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer.mm
index 288556f..70803aab 100644
--- a/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer.mm
+++ b/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer.mm
@@ -4,9 +4,8 @@
 
 #include "ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer.h"
 
-#include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_keyed_service.h"
-#include "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_keyed_service_factory.h"
+#include "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager.h"
+#import "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_observer_bridge.h"
 #include "ios/chrome/browser/crash_report/breakpad_helper.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -22,11 +21,17 @@
 }
 
 @interface CrashReporterBreadcrumbObserver () {
-  // Map associating the observed ChromeBrowserStates with the corresponding
+  // Map associating the observed BreadcrumbManager with the corresponding
   // observer bridge instances.
-  std::map<ios::ChromeBrowserState*,
-           std::unique_ptr<BreadcrumbManagerObserverBridge>>
+  std::map<BreadcrumbManager*, std::unique_ptr<BreadcrumbManagerObserverBridge>>
       _breadcrumbManagerObservers;
+
+  // Map associating the observed BreadcrumbManagerKeyedServices with the
+  // corresponding observer bridge instances.
+  std::map<BreadcrumbManagerKeyedService*,
+           std::unique_ptr<BreadcrumbManagerObserverBridge>>
+      _breadcrumbManagerServiceObservers;
+
   // A string which stores the received breadcrumbs. Since breakpad will
   // truncate this string anyway, it is truncated when a new event is added in
   // order to reduce overall memory usage.
@@ -49,17 +54,30 @@
   return self;
 }
 
-- (void)observeBrowserState:(ios::ChromeBrowserState*)browserState {
-  DCHECK(!_breadcrumbManagerObservers[browserState]);
+- (void)observeBreadcrumbManager:(BreadcrumbManager*)breadcrumbManager {
+  DCHECK(!_breadcrumbManagerObservers[breadcrumbManager]);
 
-  BreadcrumbManagerKeyedService* service =
-      BreadcrumbManagerKeyedServiceFactory::GetForBrowserState(browserState);
-  _breadcrumbManagerObservers[browserState] =
-      std::make_unique<BreadcrumbManagerObserverBridge>(service, self);
+  _breadcrumbManagerObservers[breadcrumbManager] =
+      std::make_unique<BreadcrumbManagerObserverBridge>(breadcrumbManager,
+                                                        self);
 }
 
-- (void)stopObservingBrowserState:(ios::ChromeBrowserState*)browserState {
-  _breadcrumbManagerObservers[browserState] = nullptr;
+- (void)stopObservingBreadcrumbManager:(BreadcrumbManager*)breadcrumbManager {
+  _breadcrumbManagerObservers.erase(breadcrumbManager);
+}
+
+- (void)observeBreadcrumbManagerService:
+    (BreadcrumbManagerKeyedService*)breadcrumbManagerService {
+  DCHECK(!_breadcrumbManagerServiceObservers[breadcrumbManagerService]);
+
+  _breadcrumbManagerServiceObservers[breadcrumbManagerService] =
+      std::make_unique<BreadcrumbManagerObserverBridge>(
+          breadcrumbManagerService, self);
+}
+
+- (void)stopObservingBreadcrumbManagerService:
+    (BreadcrumbManagerKeyedService*)breadcrumbManagerService {
+  _breadcrumbManagerServiceObservers[breadcrumbManagerService] = nullptr;
 }
 
 #pragma mark - BreadcrumbManagerObserving protocol
diff --git a/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer_unittest.mm b/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer_unittest.mm
index ae2ae76..ea5893a 100644
--- a/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer_unittest.mm
+++ b/ios/chrome/browser/crash_report/crash_reporter_breadcrumb_observer_unittest.mm
@@ -95,15 +95,13 @@
   [[mock_breakpad_controller_ expect] start:NO];
   breakpad_helper::SetEnabled(true);
 
-  CrashReporterBreadcrumbObserver* crash_reporter_breadcrumb_observer =
-      [[CrashReporterBreadcrumbObserver alloc] init];
-  [crash_reporter_breadcrumb_observer
-      observeBrowserState:chrome_browser_state_.get()];
-
-  const std::string event = std::string("Breadcrumb Event");
   BreadcrumbManagerKeyedService* breadcrumb_service =
       BreadcrumbManagerKeyedServiceFactory::GetForBrowserState(
           chrome_browser_state_.get());
+  CrashReporterBreadcrumbObserver* crash_reporter_breadcrumb_observer =
+      [[CrashReporterBreadcrumbObserver alloc] init];
+  [crash_reporter_breadcrumb_observer
+      observeBreadcrumbManagerService:breadcrumb_service];
 
   id breadcrumbs_param_vaidation_block = [OCMArg checkWithBlock:^(id value) {
     if (![value isKindOfClass:[NSString class]]) {
@@ -121,7 +119,7 @@
       addUploadParameter:breadcrumbs_param_vaidation_block
                   forKey:@"browser_state_breadcrumbs"];
 
-  breadcrumb_service->AddEvent(event);
+  breadcrumb_service->AddEvent(std::string("Breadcrumb Event"));
   EXPECT_OCMOCK_VERIFY(mock_breakpad_controller_);
 }
 
@@ -136,14 +134,13 @@
   const std::string event = std::string("Breadcrumb Event");
   NSString* event_nsstring = base::SysUTF8ToNSString(event);
 
-  CrashReporterBreadcrumbObserver* crash_reporter_breadcrumb_observer =
-      [[CrashReporterBreadcrumbObserver alloc] init];
-
-  [crash_reporter_breadcrumb_observer
-      observeBrowserState:chrome_browser_state_.get()];
   BreadcrumbManagerKeyedService* breadcrumb_service =
       BreadcrumbManagerKeyedServiceFactory::GetForBrowserState(
           chrome_browser_state_.get());
+  CrashReporterBreadcrumbObserver* crash_reporter_breadcrumb_observer =
+      [[CrashReporterBreadcrumbObserver alloc] init];
+  [crash_reporter_breadcrumb_observer
+      observeBreadcrumbManagerService:breadcrumb_service];
 
   [[mock_breakpad_controller_ expect]
       addUploadParameter:StringParameterValidatorWithCountOfSubstring(
@@ -153,10 +150,11 @@
 
   ios::ChromeBrowserState* otr_browser_state =
       chrome_browser_state_->GetOffTheRecordChromeBrowserState();
-  [crash_reporter_breadcrumb_observer observeBrowserState:otr_browser_state];
   BreadcrumbManagerKeyedService* otr_breadcrumb_service =
       BreadcrumbManagerKeyedServiceFactory::GetForBrowserState(
           otr_browser_state);
+  [crash_reporter_breadcrumb_observer
+      observeBreadcrumbManagerService:otr_breadcrumb_service];
 
   [[mock_breakpad_controller_ expect]
       addUploadParameter:StringParameterValidatorWithCountOfSubstring(
@@ -167,11 +165,11 @@
   TestChromeBrowserState::Builder test_cbs_builder;
   std::unique_ptr<TestChromeBrowserState> chrome_browser_state_2 =
       test_cbs_builder.Build();
-  [crash_reporter_breadcrumb_observer
-      observeBrowserState:chrome_browser_state_2.get()];
   BreadcrumbManagerKeyedService* breadcrumb_service_2 =
       BreadcrumbManagerKeyedServiceFactory::GetForBrowserState(
           chrome_browser_state_2.get());
+  [crash_reporter_breadcrumb_observer
+      observeBreadcrumbManagerService:breadcrumb_service_2];
 
   [[mock_breakpad_controller_ expect]
       addUploadParameter:StringParameterValidatorWithCountOfSubstring(
diff --git a/ios/chrome/browser/flags/about_flags.mm b/ios/chrome/browser/flags/about_flags.mm
index 6ec7371..2e9bdda 100644
--- a/ios/chrome/browser/flags/about_flags.mm
+++ b/ios/chrome/browser/flags/about_flags.mm
@@ -593,6 +593,10 @@
     {"clear-synced-data", flag_descriptions::kClearSyncedDataName,
      flag_descriptions::kClearSyncedDataDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kClearSyncedData)},
+    {"ssl-committed-interstitials",
+     flag_descriptions::kSSLCommittedInterstitialsName,
+     flag_descriptions::kSSLCommittedInterstitialsDescription, flags_ui::kOsIos,
+     FEATURE_VALUE_TYPE(web::features::kSSLCommittedInterstitials)},
 };
 
 // Add all switches from experimental flags to |command_line|.
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
index ac4cf54..e2afe0c 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.cc
@@ -344,6 +344,12 @@
 const char kSnapshotDrawViewDescription[] =
     "When enabled, snapshots will be taken using |-drawViewHierarchy:|.";
 
+const char kSSLCommittedInterstitialsName[] =
+    "Enable SSL committed interstitials";
+const char kSSLCommittedInterstitialsDescription[] =
+    "When enabled, SSL interstitial pages will be committed rather than using "
+    "an overlay on the page.";
+
 const char kForceStartupSigninPromoName[] = "Display the startup sign-in promo";
 const char kForceStartupSigninPromoDescription[] =
     "When enabled, the startup sign-in promo is always displayed when starting "
diff --git a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
index a5f3da0..16b5fa8 100644
--- a/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/flags/ios_chrome_flag_descriptions.h
@@ -303,6 +303,10 @@
 extern const char kSnapshotDrawViewName[];
 extern const char kSnapshotDrawViewDescription[];
 
+// Title and description for the flag to enable SSL committed interstitials.
+extern const char kSSLCommittedInterstitialsName[];
+extern const char kSSLCommittedInterstitialsDescription[];
+
 // Title and description for the flag to trigger the startup sign-in promo.
 extern const char kForceStartupSigninPromoName[];
 extern const char kForceStartupSigninPromoDescription[];
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_util.mm b/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_util.mm
index b6c4e75ee..f08b05b5 100644
--- a/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_util.mm
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/infobar_overlay_browser_agent_util.mm
@@ -20,7 +20,7 @@
   InfobarOverlayBrowserAgent* browser_agent =
       InfobarOverlayBrowserAgent::FromBrowser(browser);
   browser_agent->AddInfobarInteractionHandler(
-      std::make_unique<PasswordInfobarInteractionHandler>());
+      std::make_unique<PasswordInfobarInteractionHandler>(browser));
   // TODO(crbug.com/1030357): Add InfobarInteractionHandlers for each
   // InfobarType when implemented.
 }
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/BUILD.gn b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/BUILD.gn
index a249a4a9..2820a301 100644
--- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/BUILD.gn
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/BUILD.gn
@@ -21,10 +21,12 @@
     "//ios/chrome/browser/infobars/overlays:util",
     "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers",
     "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common",
+    "//ios/chrome/browser/main:public",
     "//ios/chrome/browser/overlays",
     "//ios/chrome/browser/overlays/public/infobar_banner",
     "//ios/chrome/browser/overlays/public/infobar_modal",
     "//ios/chrome/browser/passwords:infobar_delegates",
+    "//ios/chrome/browser/ui/commands",
   ]
 }
 
@@ -46,15 +48,21 @@
     "//ios/chrome/browser/infobars:public",
     "//ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/test",
     "//ios/chrome/browser/infobars/test",
+    "//ios/chrome/browser/main:test_support",
     "//ios/chrome/browser/overlays",
     "//ios/chrome/browser/overlays/public/common/infobars",
     "//ios/chrome/browser/overlays/public/infobar_modal",
     "//ios/chrome/browser/overlays/test",
     "//ios/chrome/browser/passwords:infobar_delegates",
     "//ios/chrome/browser/passwords/test",
+    "//ios/chrome/browser/ui/commands",
     "//ios/chrome/browser/ui/infobars/test",
+    "//ios/chrome/browser/web_state_list",
+    "//ios/chrome/browser/web_state_list:test_support",
     "//ios/chrome/test:test_support",
+    "//ios/web/public/test",
     "//ios/web/public/test/fakes",
     "//testing/gtest",
+    "//third_party/ocmock",
   ]
 }
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_interaction_handler.h
index 4697defc..4db9c91a 100644
--- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_interaction_handler.h
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_interaction_handler.h
@@ -9,11 +9,13 @@
 
 #import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/infobar_interaction_handler.h"
 
+class Browser;
+
 // An InfobarInteractionHandler that updates the model layer for interaction
 // events with the UI for password infobars.
 class PasswordInfobarInteractionHandler : public InfobarInteractionHandler {
  public:
-  PasswordInfobarInteractionHandler();
+  PasswordInfobarInteractionHandler(Browser* browser);
   ~PasswordInfobarInteractionHandler() override;
 };
 
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_interaction_handler.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_interaction_handler.mm
index 22a901c..c6b5292a 100644
--- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_interaction_handler.mm
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_interaction_handler.mm
@@ -13,12 +13,13 @@
 #error "This file requires ARC support."
 #endif
 
-PasswordInfobarInteractionHandler::PasswordInfobarInteractionHandler()
+PasswordInfobarInteractionHandler::PasswordInfobarInteractionHandler(
+    Browser* browser)
     : InfobarInteractionHandler(
           InfobarType::kInfobarTypePasswordSave,
           std::make_unique<PasswordInfobarBannerInteractionHandler>(),
           /*sheet_handler=*/nullptr,
-          std::make_unique<PasswordInfobarModalInteractionHandler>()) {}
+          std::make_unique<PasswordInfobarModalInteractionHandler>(browser)) {}
 
 PasswordInfobarInteractionHandler::~PasswordInfobarInteractionHandler() =
     default;
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_interaction_handler.h b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_interaction_handler.h
index 50c58649..29dbfc0d 100644
--- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_interaction_handler.h
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_interaction_handler.h
@@ -7,12 +7,14 @@
 
 #import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/common/infobar_modal_interaction_handler.h"
 
+@protocol ApplicationSettingsCommands;
+class Browser;
 class IOSChromeSavePasswordInfoBarDelegate;
 
 class PasswordInfobarModalInteractionHandler
     : public InfobarModalInteractionHandler {
  public:
-  PasswordInfobarModalInteractionHandler();
+  PasswordInfobarModalInteractionHandler(Browser* browser);
   ~PasswordInfobarModalInteractionHandler() override;
 
   // Instructs the handler to update the credentials with |username| and
@@ -43,6 +45,12 @@
   // InfobarInteractionHandler::Handler:
   void InfobarVisibilityChanged(InfoBarIOS* infobar, bool visible) override;
 
+ protected:
+  // TODO(crbug.com/1040653): This class is only subclassed as a mock for use in
+  // tests.  This constructor can be removed once the password infobar delegate
+  // is refactored for testing and this class no longer needs to be mocked.
+  PasswordInfobarModalInteractionHandler();
+
  private:
   // InfobarModalInteractionHandler:
   std::unique_ptr<InfobarModalOverlayRequestCallbackInstaller>
@@ -50,6 +58,9 @@
 
   // Returns the password delegate from |infobar|.
   IOSChromeSavePasswordInfoBarDelegate* GetDelegate(InfoBarIOS* infobar);
+
+  // Dispatcher used to open the password settings.
+  id<ApplicationSettingsCommands> settings_command_handler_ = nil;
 };
 
 #endif  // IOS_CHROME_BROWSER_INFOBARS_OVERLAYS_BROWSER_AGENT_INTERACTION_HANDLERS_PASSWORDS_PASSWORD_INFOBAR_MODAL_INTERACTION_HANDLER_H_
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_interaction_handler.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_interaction_handler.mm
index 5ef4334..5c305577 100644
--- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_interaction_handler.mm
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_interaction_handler.mm
@@ -6,7 +6,10 @@
 
 #include "ios/chrome/browser/infobars/infobar_ios.h"
 #import "ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_overlay_request_callback_installer.h"
+#include "ios/chrome/browser/main/browser.h"
 #import "ios/chrome/browser/passwords/ios_chrome_save_password_infobar_delegate.h"
+#include "ios/chrome/browser/ui/commands/application_commands.h"
+#import "ios/chrome/browser/ui/commands/command_dispatcher.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -15,6 +18,14 @@
 PasswordInfobarModalInteractionHandler::
     PasswordInfobarModalInteractionHandler() = default;
 
+PasswordInfobarModalInteractionHandler::PasswordInfobarModalInteractionHandler(
+    Browser* browser)
+    : settings_command_handler_(
+          HandlerForProtocol(browser->GetCommandDispatcher(),
+                             ApplicationSettingsCommands)) {
+  DCHECK(settings_command_handler_);
+}
+
 PasswordInfobarModalInteractionHandler::
     ~PasswordInfobarModalInteractionHandler() = default;
 
@@ -34,7 +45,7 @@
 
 void PasswordInfobarModalInteractionHandler::PresentPasswordsSettings(
     InfoBarIOS* infobar) {
-  // TODO(crbug.com/1033154): Show the passwords settings.
+  [settings_command_handler_ showSavedPasswordsSettingsFromViewController:nil];
 }
 
 void PasswordInfobarModalInteractionHandler::PerformMainAction(
diff --git a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_interaction_handler_unittest.mm b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_interaction_handler_unittest.mm
index e86bab7..3e3b115 100644
--- a/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_interaction_handler_unittest.mm
+++ b/ios/chrome/browser/infobars/overlays/browser_agent/interaction_handlers/passwords/password_infobar_modal_interaction_handler_unittest.mm
@@ -7,10 +7,19 @@
 #include "base/test/scoped_feature_list.h"
 #include "components/infobars/core/infobar_feature.h"
 #import "ios/chrome/browser/infobars/test/fake_infobar_ios.h"
+#import "ios/chrome/browser/main/test_browser.h"
 #import "ios/chrome/browser/overlays/public/overlay_request_queue.h"
 #import "ios/chrome/browser/passwords/test/mock_ios_chrome_save_passwords_infobar_delegate.h"
+#import "ios/chrome/browser/ui/commands/application_commands.h"
+#import "ios/chrome/browser/ui/commands/command_dispatcher.h"
 #import "ios/chrome/browser/ui/infobars/test/fake_infobar_ui_delegate.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/web/public/test/fakes/test_web_state.h"
+#include "ios/web/public/test/web_task_environment.h"
 #include "testing/platform_test.h"
+#import "third_party/ocmock/OCMock/OCMock.h"
+#import "third_party/ocmock/gtest_support.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -20,11 +29,23 @@
 class PasswordInfobarModalInteractionHandlerTest : public PlatformTest {
  public:
   PasswordInfobarModalInteractionHandlerTest()
-      : infobar_(
+      : mock_command_receiver_(
+            OCMStrictProtocolMock(@protocol(ApplicationSettingsCommands))),
+        infobar_(
             [[FakeInfobarUIDelegate alloc] init],
             MockIOSChromeSavePasswordInfoBarDelegate::Create(@"username",
                                                              @"password")) {
     scoped_feature_list_.InitWithFeatures({kIOSInfobarUIReboot}, {});
+    [browser_.GetCommandDispatcher()
+        startDispatchingToTarget:mock_command_receiver_
+                     forProtocol:@protocol(ApplicationSettingsCommands)];
+    handler_ =
+        std::make_unique<PasswordInfobarModalInteractionHandler>(&browser_);
+  }
+  ~PasswordInfobarModalInteractionHandlerTest() override {
+    [browser_.GetCommandDispatcher()
+        stopDispatchingToTarget:mock_command_receiver_];
+    EXPECT_OCMOCK_VERIFY(mock_command_receiver_);
   }
 
   MockIOSChromeSavePasswordInfoBarDelegate& mock_delegate() {
@@ -34,8 +55,11 @@
 
  protected:
   base::test::ScopedFeatureList scoped_feature_list_;
+  web::WebTaskEnvironment task_environment_;
+  TestBrowser browser_;
+  id mock_command_receiver_ = nil;
   InfoBarIOS infobar_;
-  PasswordInfobarModalInteractionHandler handler_;
+  std::unique_ptr<PasswordInfobarModalInteractionHandler> handler_;
 };
 
 // Tests that UpdateCredentials() forwards the call to the mock delegate.
@@ -43,13 +67,20 @@
   NSString* username = @"username";
   NSString* password = @"password";
   EXPECT_CALL(mock_delegate(), UpdateCredentials(username, password));
-  handler_.UpdateCredentials(&infobar_, username, password);
+  handler_->UpdateCredentials(&infobar_, username, password);
 }
 
 // Tests that NeverSaveCredentials() forwards the call to the mock delegate.
 TEST_F(PasswordInfobarModalInteractionHandlerTest, NeverSaveCredentials) {
   EXPECT_CALL(mock_delegate(), Cancel());
-  handler_.NeverSaveCredentials(&infobar_);
+  handler_->NeverSaveCredentials(&infobar_);
+}
+
+// Tests that PresentPasswordsSettings() forwards the call to the mock delegate.
+TEST_F(PasswordInfobarModalInteractionHandlerTest, PresentPasswordsSettings) {
+  OCMExpect([mock_command_receiver_
+      showSavedPasswordsSettingsFromViewController:nil]);
+  handler_->PresentPasswordsSettings(&infobar_);
 }
 
 // Tests PerformMainAction() calls Accept() on the mock delegate and resets
@@ -57,7 +88,7 @@
 TEST_F(PasswordInfobarModalInteractionHandlerTest, MainAction) {
   ASSERT_FALSE(infobar_.accepted());
   EXPECT_CALL(mock_delegate(), Accept()).WillOnce(testing::Return(true));
-  handler_.PerformMainAction(&infobar_);
+  handler_->PerformMainAction(&infobar_);
   EXPECT_TRUE(infobar_.accepted());
 }
 
@@ -65,7 +96,7 @@
 // InfobarDismissed() on the mock delegate.
 TEST_F(PasswordInfobarModalInteractionHandlerTest, InfobarVisibilityChanged) {
   EXPECT_CALL(mock_delegate(), InfobarPresenting(/*automatic=*/false));
-  handler_.InfobarVisibilityChanged(&infobar_, true);
+  handler_->InfobarVisibilityChanged(&infobar_, true);
   EXPECT_CALL(mock_delegate(), InfobarDismissed());
-  handler_.InfobarVisibilityChanged(&infobar_, false);
+  handler_->InfobarVisibilityChanged(&infobar_, false);
 }
diff --git a/ios/chrome/browser/ui/bubble/bubble_presenter.h b/ios/chrome/browser/ui/bubble/bubble_presenter.h
index e6655b1..b1b3ca7 100644
--- a/ios/chrome/browser/ui/bubble/bubble_presenter.h
+++ b/ios/chrome/browser/ui/bubble/bubble_presenter.h
@@ -7,9 +7,7 @@
 
 #import <UIKit/UIKit.h>
 
-namespace ios {
-class ChromeBrowserState;
-}
+#include "ios/chrome/browser/browser_state/chrome_browser_state_forward.h"
 
 @protocol BubblePresenterDelegate;
 @class BubbleViewControllerPresenter;
diff --git a/ios/chrome/browser/ui/main/BUILD.gn b/ios/chrome/browser/ui/main/BUILD.gn
index 982ce12..f493b04 100644
--- a/ios/chrome/browser/ui/main/BUILD.gn
+++ b/ios/chrome/browser/ui/main/BUILD.gn
@@ -41,6 +41,9 @@
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/browsing_data",
     "//ios/chrome/browser/crash_report",
+    "//ios/chrome/browser/crash_report:crash_report_internal",
+    "//ios/chrome/browser/crash_report/breadcrumbs",
+    "//ios/chrome/browser/crash_report/breadcrumbs:feature_flags",
     "//ios/chrome/browser/main",
     "//ios/chrome/browser/ntp:features",
     "//ios/chrome/browser/payments",
@@ -87,8 +90,6 @@
     "//ios/chrome/browser/browser_state",
     "//ios/chrome/browser/browsing_data",
     "//ios/chrome/browser/crash_report:crash_report_internal",
-    "//ios/chrome/browser/crash_report/breadcrumbs",
-    "//ios/chrome/browser/crash_report/breadcrumbs:feature_flags",
     "//ios/chrome/browser/device_sharing",
     "//ios/chrome/browser/download",
     "//ios/chrome/browser/main",
diff --git a/ios/chrome/browser/ui/main/browser_view_wrangler.mm b/ios/chrome/browser/ui/main/browser_view_wrangler.mm
index f7627af..20e9420b 100644
--- a/ios/chrome/browser/ui/main/browser_view_wrangler.mm
+++ b/ios/chrome/browser/ui/main/browser_view_wrangler.mm
@@ -9,8 +9,6 @@
 #include "base/strings/sys_string_conversions.h"
 #include "ios/chrome/browser/application_context.h"
 #include "ios/chrome/browser/browser_state/chrome_browser_state.h"
-#include "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_browser_agent.h"
-#include "ios/chrome/browser/crash_report/breadcrumbs/features.h"
 #include "ios/chrome/browser/crash_report/crash_report_helper.h"
 #import "ios/chrome/browser/device_sharing/device_sharing_manager.h"
 #import "ios/chrome/browser/main/browser.h"
@@ -165,9 +163,6 @@
                          (id<BrowserStateStorageSwitching>)storageSwitcher {
   if ((self = [super init])) {
     _browserState = browserState;
-    if (base::FeatureList::IsEnabled(kLogBreadcrumbs)) {
-      breakpad::MonitorBreadcrumbsForBrowserState(_browserState);
-    }
     _applicationCommandEndpoint = applicationCommandEndpoint;
     _browsingDataCommandEndpoint = browsingDataCommandEndpoint;
     _appURLLoadingService = appURLLoadingService;
@@ -269,10 +264,6 @@
   if (_mainBrowser.get()) {
     TabModel* tabModel = self.mainBrowser->GetTabModel();
     WebStateList* webStateList = self.mainBrowser->GetWebStateList();
-    if (base::FeatureList::IsEnabled(kLogBreadcrumbs)) {
-      BreadcrumbManagerBrowserAgent::FromBrowser(self.mainBrowser)
-          ->SetLoggingEnabled(false);
-    }
     breakpad::StopMonitoringTabStateForWebStateList(webStateList);
     breakpad::StopMonitoringURLsForWebStateList(webStateList);
     [tabModel disconnect];
@@ -288,10 +279,6 @@
   if (_otrBrowser.get()) {
     TabModel* tabModel = self.otrBrowser->GetTabModel();
     WebStateList* webStateList = self.otrBrowser->GetWebStateList();
-    if (base::FeatureList::IsEnabled(kLogBreadcrumbs)) {
-      BreadcrumbManagerBrowserAgent::FromBrowser(self.otrBrowser)
-          ->SetLoggingEnabled(false);
-    }
     breakpad::StopMonitoringTabStateForWebStateList(webStateList);
     [tabModel disconnect];
     _activeWebStateObservationForwarders[webStateList] = nullptr;
@@ -365,10 +352,6 @@
   // Stop watching the OTR webStateList's state for crashes.
   breakpad::StopMonitoringTabStateForWebStateList(
       self.otrBrowser->GetWebStateList());
-  if (base::FeatureList::IsEnabled(kLogBreadcrumbs)) {
-    breakpad::StopMonitoringBreadcrumbsForBrowserState(
-        self.otrBrowser->GetBrowserState());
-  }
 
   // At this stage, a new incognitoBrowserCoordinator shouldn't be lazily
   // constructed by calling the property getter.
@@ -429,13 +412,6 @@
   [self setMainBrowser:nullptr];
   [self setOtrBrowser:nullptr];
 
-  if (base::FeatureList::IsEnabled(kLogBreadcrumbs)) {
-    if (_browserState->HasOffTheRecordChromeBrowserState()) {
-      breakpad::StopMonitoringBreadcrumbsForBrowserState(
-          _browserState->GetOffTheRecordChromeBrowserState());
-    }
-    breakpad::StopMonitoringBreadcrumbsForBrowserState(_browserState);
-  }
   _browserState = nullptr;
 }
 
@@ -447,9 +423,6 @@
   ios::ChromeBrowserState* otrBrowserState =
       _browserState->GetOffTheRecordChromeBrowserState();
   DCHECK(otrBrowserState);
-  if (base::FeatureList::IsEnabled(kLogBreadcrumbs)) {
-    breakpad::MonitorBreadcrumbsForBrowserState(otrBrowserState);
-  }
 
   std::unique_ptr<Browser> browser = Browser::Create(otrBrowserState);
   BrowserList* browserList =
diff --git a/ios/chrome/browser/ui/main/scene_controller.mm b/ios/chrome/browser/ui/main/scene_controller.mm
index 4f5dae13..c1f7323 100644
--- a/ios/chrome/browser/ui/main/scene_controller.mm
+++ b/ios/chrome/browser/ui/main/scene_controller.mm
@@ -24,7 +24,12 @@
 #include "ios/chrome/browser/browsing_data/browsing_data_remover_factory.h"
 #include "ios/chrome/browser/chrome_url_constants.h"
 #import "ios/chrome/browser/chrome_url_util.h"
+#include "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_browser_agent.h"
+#include "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_keyed_service.h"
+#include "ios/chrome/browser/crash_report/breadcrumbs/breadcrumb_manager_keyed_service_factory.h"
+#include "ios/chrome/browser/crash_report/breadcrumbs/features.h"
 #include "ios/chrome/browser/crash_report/breakpad_helper.h"
+#include "ios/chrome/browser/crash_report/crash_report_helper.h"
 #include "ios/chrome/browser/main/browser.h"
 #include "ios/chrome/browser/ntp/features.h"
 #include "ios/chrome/browser/payments/ios_payment_instrument_launcher.h"
@@ -479,6 +484,11 @@
 // TODO(crbug.com/779791) : Remove show settings commands from MainController.
 - (void)showSavedPasswordsSettingsFromViewController:
     (UIViewController*)baseViewController {
+  if (!baseViewController) {
+    // TODO(crbug.com/779791): Don't pass base view controller through
+    // dispatched command.
+    baseViewController = [self.mainController currentBVC];
+  }
   DCHECK(!self.signinInteractionCoordinator.isSettingsViewPresented);
   if (self.settingsNavigationController) {
     [self.settingsNavigationController
@@ -1287,19 +1297,35 @@
   BOOL otrBVCIsCurrent = (self.interfaceProvider.mainInterface.bvc ==
                           self.interfaceProvider.incognitoInterface.bvc);
 
-  // Clear the OTR tab model and notify the _tabSwitcher that its otrBVC will
-  // be destroyed.
+  // Clear the Incognito Browser and notify the _tabSwitcher that its otrBrowser
+  // will be destroyed.
   [self.mainController.tabSwitcher setOtrBrowser:nil];
 
+  if (base::FeatureList::IsEnabled(kLogBreadcrumbs)) {
+    BreadcrumbManagerBrowserAgent::FromBrowser(self.incognitoInterface.browser)
+        ->SetLoggingEnabled(false);
+
+    breakpad::StopMonitoringBreadcrumbManagerService(
+        BreadcrumbManagerKeyedServiceFactory::GetForBrowserState(
+            self.incognitoInterface.browserState));
+  }
+
   [self.mainController.browserViewWrangler destroyAndRebuildIncognitoBrowser];
 
+  if (base::FeatureList::IsEnabled(kLogBreadcrumbs)) {
+    breakpad::MonitorBreadcrumbManagerService(
+        BreadcrumbManagerKeyedServiceFactory::GetForBrowserState(
+            self.incognitoInterface.browserState));
+  }
+
   if (otrBVCIsCurrent) {
     [self activateBVCAndMakeCurrentBVCPrimary];
   }
 
-  // Always set the new otr tab model for the tablet or grid switcher.
-  // Notify the _tabSwitcher with the new otrBVC.
-  [self.mainController.tabSwitcher setOtrBrowser:self.mainInterface.browser];
+  // Always set the new otr Browser for the tablet or grid switcher.
+  // Notify the _tabSwitcher with the new Incognito Browser.
+  [self.mainController.tabSwitcher
+      setOtrBrowser:self.incognitoInterface.browser];
 
   // This seems the best place to deem the destroying and rebuilding the
   // incognito browser state to be completed.
diff --git a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
index c075f337..db2dfae 100644
--- a/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
+++ b/media/gpu/v4l2/v4l2_slice_video_decode_accelerator.cc
@@ -2160,7 +2160,7 @@
     // imported frame into another one that we can destruct.
     scoped_refptr<VideoFrame> wrapped_frame = VideoFrame::WrapVideoFrame(
         output_frame, output_frame->format(), output_frame->visible_rect(),
-        output_frame->coded_size());
+        output_frame->visible_rect().size());
     DCHECK(wrapped_frame);
 
     image_processor_->Process(
diff --git a/media/gpu/vaapi/vaapi_picture.cc b/media/gpu/vaapi/vaapi_picture.cc
index f3236a4..c9d5d22 100644
--- a/media/gpu/vaapi/vaapi_picture.cc
+++ b/media/gpu/vaapi/vaapi_picture.cc
@@ -18,6 +18,7 @@
     const BindGLImageCallback& bind_image_cb,
     int32_t picture_buffer_id,
     const gfx::Size& size,
+    const gfx::Size& visible_size,
     uint32_t texture_id,
     uint32_t client_texture_id,
     uint32_t texture_target)
@@ -25,6 +26,7 @@
       make_context_current_cb_(make_context_current_cb),
       bind_image_cb_(bind_image_cb),
       size_(size),
+      visible_size_(visible_size),
       texture_id_(texture_id),
       client_texture_id_(client_texture_id),
       texture_target_(texture_target),
diff --git a/media/gpu/vaapi/vaapi_picture.h b/media/gpu/vaapi/vaapi_picture.h
index 0ae1e3c..0364163 100644
--- a/media/gpu/vaapi/vaapi_picture.h
+++ b/media/gpu/vaapi/vaapi_picture.h
@@ -59,6 +59,7 @@
                const BindGLImageCallback& bind_image_cb,
                int32_t picture_buffer_id,
                const gfx::Size& size,
+               const gfx::Size& visible_size,
                uint32_t texture_id,
                uint32_t client_texture_id,
                uint32_t texture_target);
@@ -69,6 +70,7 @@
   const BindGLImageCallback bind_image_cb_;
 
   const gfx::Size size_;
+  const gfx::Size visible_size_;
   const uint32_t texture_id_;
   const uint32_t client_texture_id_;
   const uint32_t texture_target_;
diff --git a/media/gpu/vaapi/vaapi_picture_factory.cc b/media/gpu/vaapi/vaapi_picture_factory.cc
index 77a5242..ea01697 100644
--- a/media/gpu/vaapi/vaapi_picture_factory.cc
+++ b/media/gpu/vaapi/vaapi_picture_factory.cc
@@ -44,7 +44,8 @@
     scoped_refptr<VaapiWrapper> vaapi_wrapper,
     const MakeGLContextCurrentCallback& make_context_current_cb,
     const BindGLImageCallback& bind_image_cb,
-    const PictureBuffer& picture_buffer) {
+    const PictureBuffer& picture_buffer,
+    const gfx::Size& visible_size) {
   // ARC++ sends |picture_buffer| with no texture_target().
   DCHECK(picture_buffer.texture_target() == GetGLTextureTarget() ||
          picture_buffer.texture_target() == 0u);
@@ -70,15 +71,17 @@
     case kVaapiImplementationDrm:
       picture.reset(new VaapiPictureNativePixmapOzone(
           std::move(vaapi_wrapper), make_context_current_cb, bind_image_cb,
-          picture_buffer.id(), picture_buffer.size(), service_texture_id,
-          client_texture_id, picture_buffer.texture_target()));
+          picture_buffer.id(), picture_buffer.size(), visible_size,
+          service_texture_id, client_texture_id,
+          picture_buffer.texture_target()));
       break;
 #elif defined(USE_EGL)
     case kVaapiImplementationDrm:
       picture.reset(new VaapiPictureNativePixmapEgl(
           std::move(vaapi_wrapper), make_context_current_cb, bind_image_cb,
-          picture_buffer.id(), picture_buffer.size(), service_texture_id,
-          client_texture_id, picture_buffer.texture_target()));
+          picture_buffer.id(), picture_buffer.size(), visible_size,
+          service_texture_id, client_texture_id,
+          picture_buffer.texture_target()));
       break;
 #endif
 
@@ -86,8 +89,9 @@
     case kVaapiImplementationX11:
       picture.reset(new VaapiTFPPicture(
           std::move(vaapi_wrapper), make_context_current_cb, bind_image_cb,
-          picture_buffer.id(), picture_buffer.size(), service_texture_id,
-          client_texture_id, picture_buffer.texture_target()));
+          picture_buffer.id(), picture_buffer.size(), visible_size,
+          service_texture_id, client_texture_id,
+          picture_buffer.texture_target()));
       break;
 #endif  // USE_X11
 
diff --git a/media/gpu/vaapi/vaapi_picture_factory.h b/media/gpu/vaapi/vaapi_picture_factory.h
index 6b3867a..09edc66 100644
--- a/media/gpu/vaapi/vaapi_picture_factory.h
+++ b/media/gpu/vaapi/vaapi_picture_factory.h
@@ -36,7 +36,8 @@
       scoped_refptr<VaapiWrapper> vaapi_wrapper,
       const MakeGLContextCurrentCallback& make_context_current_cb,
       const BindGLImageCallback& bind_image_cb,
-      const PictureBuffer& picture_buffer);
+      const PictureBuffer& picture_buffer,
+      const gfx::Size& visible_size);
 
   // Return the type of the VaapiPicture implementation for the given GL
   // implementation.
diff --git a/media/gpu/vaapi/vaapi_picture_native_pixmap.cc b/media/gpu/vaapi/vaapi_picture_native_pixmap.cc
index e76693c..941f24cc 100644
--- a/media/gpu/vaapi/vaapi_picture_native_pixmap.cc
+++ b/media/gpu/vaapi/vaapi_picture_native_pixmap.cc
@@ -21,6 +21,7 @@
     const BindGLImageCallback& bind_image_cb,
     int32_t picture_buffer_id,
     const gfx::Size& size,
+    const gfx::Size& visible_size,
     uint32_t texture_id,
     uint32_t client_texture_id,
     uint32_t texture_target)
@@ -29,6 +30,7 @@
                    bind_image_cb,
                    picture_buffer_id,
                    size,
+                   visible_size,
                    texture_id,
                    client_texture_id,
                    texture_target) {}
diff --git a/media/gpu/vaapi/vaapi_picture_native_pixmap.h b/media/gpu/vaapi/vaapi_picture_native_pixmap.h
index 4904e0a..a77583a 100644
--- a/media/gpu/vaapi/vaapi_picture_native_pixmap.h
+++ b/media/gpu/vaapi/vaapi_picture_native_pixmap.h
@@ -31,6 +31,7 @@
       const BindGLImageCallback& bind_image_cb_,
       int32_t picture_buffer_id,
       const gfx::Size& size,
+      const gfx::Size& visible_size,
       uint32_t texture_id,
       uint32_t client_texture_id,
       uint32_t texture_target);
diff --git a/media/gpu/vaapi/vaapi_picture_native_pixmap_egl.cc b/media/gpu/vaapi/vaapi_picture_native_pixmap_egl.cc
index 157980c..edcd25c 100644
--- a/media/gpu/vaapi/vaapi_picture_native_pixmap_egl.cc
+++ b/media/gpu/vaapi/vaapi_picture_native_pixmap_egl.cc
@@ -21,6 +21,7 @@
     const MakeGLContextCurrentCallback& make_context_current_cb,
     const BindGLImageCallback& bind_image_cb,
     int32_t picture_buffer_id,
+    const gfx::Size& visible_size,
     const gfx::Size& size,
     uint32_t texture_id,
     uint32_t client_texture_id,
@@ -30,6 +31,7 @@
                                bind_image_cb,
                                picture_buffer_id,
                                size,
+                               visible_size,
                                texture_id,
                                client_texture_id,
                                texture_target) {
@@ -75,7 +77,8 @@
   if (make_context_current_cb_ && !make_context_current_cb_.Run())
     return false;
 
-  auto image = base::MakeRefCounted<gl::GLImageNativePixmap>(size_, format);
+  auto image =
+      base::MakeRefCounted<gl::GLImageNativePixmap>(visible_size_, format);
   // Create an EGLImage from a gl texture
   if (!image->InitializeFromTexture(texture_id_)) {
     DLOG(ERROR) << "Failed to initialize eglimage from texture id: "
@@ -90,6 +93,14 @@
     return false;
   }
 
+  if (size_.width() > static_cast<int>(native_pixmap_handle.planes[0].stride) ||
+      size_.GetArea() > static_cast<int>(native_pixmap_handle.planes[0].size)) {
+    DLOG(ERROR) << "EGLImage (stride=" << native_pixmap_handle.planes[0].stride
+                << ", size=" << native_pixmap_handle.planes[0].size
+                << "is smaller than size_=" << size_.ToString();
+    return false;
+  }
+
   // Convert NativePixmapHandle to NativePixmapDmaBuf.
   scoped_refptr<gfx::NativePixmap> native_pixmap_dmabuf(
       new gfx::NativePixmapDmaBuf(size_, format,
diff --git a/media/gpu/vaapi/vaapi_picture_native_pixmap_egl.h b/media/gpu/vaapi/vaapi_picture_native_pixmap_egl.h
index 17708683..6b838cc3 100644
--- a/media/gpu/vaapi/vaapi_picture_native_pixmap_egl.h
+++ b/media/gpu/vaapi/vaapi_picture_native_pixmap_egl.h
@@ -32,6 +32,7 @@
       const BindGLImageCallback& bind_image_cb_,
       int32_t picture_buffer_id,
       const gfx::Size& size,
+      const gfx::Size& visible_size,
       uint32_t texture_id,
       uint32_t client_texture_id,
       uint32_t texture_target);
diff --git a/media/gpu/vaapi/vaapi_picture_native_pixmap_ozone.cc b/media/gpu/vaapi/vaapi_picture_native_pixmap_ozone.cc
index 51e20c6..0e71833 100644
--- a/media/gpu/vaapi/vaapi_picture_native_pixmap_ozone.cc
+++ b/media/gpu/vaapi/vaapi_picture_native_pixmap_ozone.cc
@@ -22,6 +22,7 @@
     const BindGLImageCallback& bind_image_cb,
     int32_t picture_buffer_id,
     const gfx::Size& size,
+    const gfx::Size& visible_size,
     uint32_t texture_id,
     uint32_t client_texture_id,
     uint32_t texture_target)
@@ -30,6 +31,7 @@
                                bind_image_cb,
                                picture_buffer_id,
                                size,
+                               visible_size,
                                texture_id,
                                client_texture_id,
                                texture_target) {
@@ -71,11 +73,13 @@
 
   const gfx::BufferFormat format = pixmap->GetBufferFormat();
 
-  auto image = base::MakeRefCounted<gl::GLImageNativePixmap>(size_, format);
+  auto image =
+      base::MakeRefCounted<gl::GLImageNativePixmap>(visible_size_, format);
   if (!image->Initialize(std::move(pixmap))) {
     LOG(ERROR) << "Failed to create GLImage";
     return false;
   }
+
   gl_image_ = image;
   if (!gl_image_->BindTexImage(texture_target_)) {
     LOG(ERROR) << "Failed to bind texture to GLImage";
@@ -113,6 +117,15 @@
     gfx::GpuMemoryBufferHandle gpu_memory_buffer_handle) {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
+  const auto& plane = gpu_memory_buffer_handle.native_pixmap_handle.planes[0];
+  if (size_.width() > static_cast<int>(plane.stride) ||
+      size_.GetArea() > static_cast<int>(plane.size)) {
+    DLOG(ERROR) << "GpuMemoryBufferHandle (stride=" << plane.stride
+                << ", size=" << plane.size
+                << "is smaller than size_=" << size_.ToString();
+    return false;
+  }
+
   ui::OzonePlatform* platform = ui::OzonePlatform::GetInstance();
   ui::SurfaceFactoryOzone* factory = platform->GetSurfaceFactoryOzone();
   // CreateNativePixmapFromHandle() will take ownership of the handle.
diff --git a/media/gpu/vaapi/vaapi_picture_native_pixmap_ozone.h b/media/gpu/vaapi/vaapi_picture_native_pixmap_ozone.h
index 2aefab03..3abdc84b 100644
--- a/media/gpu/vaapi/vaapi_picture_native_pixmap_ozone.h
+++ b/media/gpu/vaapi/vaapi_picture_native_pixmap_ozone.h
@@ -31,6 +31,7 @@
       const BindGLImageCallback& bind_image_cb_,
       int32_t picture_buffer_id,
       const gfx::Size& size,
+      const gfx::Size& visible_size,
       uint32_t texture_id,
       uint32_t client_texture_id,
       uint32_t texture_target);
diff --git a/media/gpu/vaapi/vaapi_picture_tfp.cc b/media/gpu/vaapi/vaapi_picture_tfp.cc
index a42f19b..227c31b 100644
--- a/media/gpu/vaapi/vaapi_picture_tfp.cc
+++ b/media/gpu/vaapi/vaapi_picture_tfp.cc
@@ -19,6 +19,7 @@
     const BindGLImageCallback& bind_image_cb,
     int32_t picture_buffer_id,
     const gfx::Size& size,
+    const gfx::Size& visible_size,
     uint32_t texture_id,
     uint32_t client_texture_id,
     uint32_t texture_target)
@@ -27,6 +28,7 @@
                    bind_image_cb,
                    picture_buffer_id,
                    size,
+                   visible_size,
                    texture_id,
                    client_texture_id,
                    texture_target),
diff --git a/media/gpu/vaapi/vaapi_picture_tfp.h b/media/gpu/vaapi/vaapi_picture_tfp.h
index 78eb8361..830cb6e 100644
--- a/media/gpu/vaapi/vaapi_picture_tfp.h
+++ b/media/gpu/vaapi/vaapi_picture_tfp.h
@@ -30,6 +30,7 @@
                   const BindGLImageCallback& bind_image_cb,
                   int32_t picture_buffer_id,
                   const gfx::Size& size,
+                  const gfx::Size& visible_size,
                   uint32_t texture_id,
                   uint32_t client_texture_id,
                   uint32_t texture_target);
diff --git a/media/gpu/vaapi/vaapi_video_decode_accelerator.cc b/media/gpu/vaapi/vaapi_video_decode_accelerator.cc
index 5498ab8..065fdedf 100644
--- a/media/gpu/vaapi/vaapi_video_decode_accelerator.cc
+++ b/media/gpu/vaapi/vaapi_video_decode_accelerator.cc
@@ -688,7 +688,8 @@
         (buffer_allocation_mode_ == BufferAllocationMode::kNone)
             ? vaapi_wrapper_
             : vpp_vaapi_wrapper_,
-        make_context_current_cb_, bind_image_cb_, buffer);
+        make_context_current_cb_, bind_image_cb_, buffer,
+        decoder_->GetVisibleRect().size());
     RETURN_AND_NOTIFY_ON_FAILURE(picture, "Failed creating a VaapiPicture",
                                  PLATFORM_FAILURE, );
 
diff --git a/media/gpu/vaapi/vaapi_video_decode_accelerator_unittest.cc b/media/gpu/vaapi/vaapi_video_decode_accelerator_unittest.cc
index 83dcc61e..175b03b 100644
--- a/media/gpu/vaapi/vaapi_video_decode_accelerator_unittest.cc
+++ b/media/gpu/vaapi/vaapi_video_decode_accelerator_unittest.cc
@@ -89,6 +89,7 @@
                    const BindGLImageCallback& bind_image_cb,
                    int32_t picture_buffer_id,
                    const gfx::Size& size,
+                   const gfx::Size& visible_size,
                    uint32_t texture_id,
                    uint32_t client_texture_id,
                    uint32_t texture_target)
@@ -97,6 +98,7 @@
                      bind_image_cb,
                      picture_buffer_id,
                      size,
+                     visible_size,
                      texture_id,
                      client_texture_id,
                      texture_target) {}
@@ -124,19 +126,22 @@
   MockVaapiPictureFactory() = default;
   ~MockVaapiPictureFactory() override = default;
 
-  MOCK_METHOD2(MockCreateVaapiPicture, void(VaapiWrapper*, const gfx::Size&));
+  MOCK_METHOD3(MockCreateVaapiPicture,
+               void(VaapiWrapper*, const gfx::Size&, const gfx::Size&));
   std::unique_ptr<VaapiPicture> Create(
       scoped_refptr<VaapiWrapper> vaapi_wrapper,
       const MakeGLContextCurrentCallback& make_context_current_cb,
       const BindGLImageCallback& bind_image_cb,
-      const PictureBuffer& picture_buffer) override {
+      const PictureBuffer& picture_buffer,
+      const gfx::Size& visible_size) override {
     const uint32_t service_texture_id = picture_buffer.service_texture_ids()[0];
     const uint32_t client_texture_id = picture_buffer.client_texture_ids()[0];
-    MockCreateVaapiPicture(vaapi_wrapper.get(), picture_buffer.size());
+    MockCreateVaapiPicture(vaapi_wrapper.get(), picture_buffer.size(),
+                           visible_size);
     return std::make_unique<MockVaapiPicture>(
         std::move(vaapi_wrapper), make_context_current_cb, bind_image_cb,
-        picture_buffer.id(), picture_buffer.size(), service_texture_id,
-        client_texture_id, picture_buffer.texture_target());
+        picture_buffer.id(), picture_buffer.size(), visible_size,
+        service_texture_id, client_texture_id, picture_buffer.texture_target());
   }
 };
 
@@ -288,9 +293,11 @@
     if (GetParam().decode_using_client_picture_buffers) {
       EXPECT_CALL(*mock_vaapi_wrapper_, CreateContext(picture_size))
           .WillOnce(Return(true));
-      EXPECT_CALL(
-          *mock_vaapi_picture_factory_,
-          MockCreateVaapiPicture(mock_vaapi_wrapper_.get(), picture_size))
+      EXPECT_CALL(*mock_decoder_, GetVisibleRect())
+          .WillRepeatedly(Return(gfx::Rect(picture_size)));
+      EXPECT_CALL(*mock_vaapi_picture_factory_,
+                  MockCreateVaapiPicture(mock_vaapi_wrapper_.get(),
+                                         picture_size, picture_size))
           .Times(num_pictures);
     } else {
       EXPECT_EQ(
@@ -308,8 +315,10 @@
                 va_surface_ids->resize(kNumReferenceFrames);
               })),
               Return(true)));
+      EXPECT_CALL(*mock_decoder_, GetVisibleRect())
+          .WillRepeatedly(Return(gfx::Rect(picture_size)));
       EXPECT_CALL(*mock_vaapi_picture_factory_,
-                  MockCreateVaapiPicture(_, picture_size))
+                  MockCreateVaapiPicture(_, picture_size, picture_size))
           .Times(num_pictures);
     }
 
diff --git a/net/base/net_errors.cc b/net/base/net_errors.cc
index 41d8bee..1682fa6 100644
--- a/net/base/net_errors.cc
+++ b/net/base/net_errors.cc
@@ -63,8 +63,8 @@
 }
 
 bool IsHostnameResolutionError(int error) {
-  return (error == ERR_NAME_NOT_RESOLVED ||
-          error == ERR_NAME_RESOLUTION_FAILED);
+  DCHECK_NE(ERR_NAME_RESOLUTION_FAILED, error);
+  return error == ERR_NAME_NOT_RESOLVED;
 }
 
 Error FileErrorToNetError(base::File::Error file_error) {
diff --git a/net/dns/host_resolver.cc b/net/dns/host_resolver.cc
index 76b9bc6..ad7299cf 100644
--- a/net/dns/host_resolver.cc
+++ b/net/dns/host_resolver.cc
@@ -242,8 +242,12 @@
 
 // static
 int HostResolver::SquashErrorCode(int error) {
-  if (error == OK || error == ERR_IO_PENDING ||
-      error == ERR_NAME_NOT_RESOLVED) {
+  // TODO(crbug.com/1040686): Once InProcessBrowserTests do not use
+  // ERR_NOT_IMPLEMENTED to simulate DNS failures, it should be ok to squash
+  // ERR_NOT_IMPLEMENTED.
+  // TODO(crbug.com/1043281): Consider squashing ERR_INTERNET_DISCONNECTED.
+  if (error == OK || error == ERR_IO_PENDING || error == ERR_NOT_IMPLEMENTED ||
+      error == ERR_INTERNET_DISCONNECTED || error == ERR_NAME_NOT_RESOLVED) {
     return error;
   } else {
     return ERR_NAME_NOT_RESOLVED;
diff --git a/net/dns/host_resolver.h b/net/dns/host_resolver.h
index 092ac6f..264ab583 100644
--- a/net/dns/host_resolver.h
+++ b/net/dns/host_resolver.h
@@ -66,12 +66,9 @@
     // On any other returned value, the request was handled synchronously and
     // |callback| will not be invoked.
     //
-    // Results in ERR_NAME_NOT_RESOLVED if the hostname is invalid, or if it is
-    // an incompatible IP literal (e.g. IPv6 is disabled and it is an IPv6
-    // literal).
-    //
-    // Results in ERR_DNS_CACHE_MISS if only fast local sources are to be
-    // queried and a cache lookup attempt fails.
+    // Results in ERR_NAME_NOT_RESOLVED if the hostname is not resolved. More
+    // detail about the underlying error can be retrieved using
+    // GetResolveErrorInfo().
     //
     // The parent HostResolver must still be alive when Start() is called,  but
     // if it is destroyed before an asynchronous result completes, the request
diff --git a/net/dns/host_resolver_manager.cc b/net/dns/host_resolver_manager.cc
index 884d3ff..632f5b4 100644
--- a/net/dns/host_resolver_manager.cc
+++ b/net/dns/host_resolver_manager.cc
@@ -650,7 +650,7 @@
     LogFinishRequest(error);
 
     DCHECK(callback_);
-    std::move(callback_).Run(error);
+    std::move(callback_).Run(HostResolver::SquashErrorCode(error));
   }
 
   Job* job() const { return job_; }
@@ -3015,7 +3015,7 @@
                     effective_secure_dns_mode, base::TimeDelta());
     request->set_error_info(results.error(),
                             false /* is_secure_network_error */);
-    return results.error();
+    return HostResolver::SquashErrorCode(results.error());
   }
 
   CreateAndStartJob(effective_query_type, effective_host_resolver_flags,
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index 023cae1..1d113c3 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -4261,7 +4261,6 @@
     { "name": "brandon.so", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "brightstarkids.com.au", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bsidessf.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "bunbun.be", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "burtrum.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "buzzconf.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bytejail.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -5292,7 +5291,6 @@
     { "name": "codabix.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "creditkarma.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "cryptify.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "crystalchandelierservices.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "cwagner.me", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "cyberkov.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "cyberpunk.ca", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -6834,7 +6832,6 @@
     { "name": "onepluscamps.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "oneway.ga", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "onlinepollsph.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "onqproductions.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "opensrd.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "opperwall.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "opus-codium.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -7007,7 +7004,6 @@
     { "name": "umidev.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "upboard.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "ur-lauber.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "usakitchensandflooring.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "usbtypeccompliant.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "val-sec.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "valethound.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -9692,7 +9688,6 @@
     { "name": "pxx.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "pyol.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "pysays.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "qccareerschool.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "qcdesignschool.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "qceventplanning.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "qcmakeupacademy.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -11070,7 +11065,6 @@
     { "name": "nodecompat.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "niouininon.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "nippombashi.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "nowlas.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "novawave.ca", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "nordiccasinocommunity.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "norrliden.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -12861,7 +12855,6 @@
     { "name": "ingalls.run", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "ins1gn1a.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "insertcoins.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "instinctiveads.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "intafe.co.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "integraxor.com.tw", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "intencje.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -13826,7 +13819,6 @@
     { "name": "2cv-fahrer.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "al-f.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "1k8b.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "41844.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "alicestudio.it", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "4-it.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "aigcev.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -15135,7 +15127,6 @@
     { "name": "sepalandseed.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "sequiturs.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "significados.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "sift-tool.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "shux.pro", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "skyline.link", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "selectary.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -16917,7 +16908,6 @@
     { "name": "analyticsinmotion.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "androticsdirect.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "alfa-tech.su", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "adrianseo.ro", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "alfa24.pro", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "anotherfatgeek.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "alisonisrealestate.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -18775,7 +18765,6 @@
     { "name": "threecrownsllp.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "thetrendspotter.net", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "tofilmhub.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "tarsashaz-biztositas.hu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "tloxygen.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "thriveta.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "tosainu.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -22059,7 +22048,6 @@
     { "name": "l0re.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "lambauer.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "lanna.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "lasrecetasdeguada.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "lastrada-minden.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "law-peters.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "lawrence-institute.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -22454,7 +22442,6 @@
     { "name": "touchscreen-handy.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "tpms4u.at", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "trabajarenperu.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "trabajarenremoto.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "tracalada.cl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "transl8.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "travel-kuban.ru", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -22709,7 +22696,6 @@
     { "name": "adlerweb.info", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "administratorserwera.pl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "admongo.gov", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "adnseguros.es", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "adrafinil.wiki", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "adriancohea.ninja", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "advantagehomeexteriors.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -22831,7 +22817,6 @@
     { "name": "anymetrix.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "anyon.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "aozora.moe", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "apertis.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "apila.care", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "aplikaceproandroid.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "aplu.fr", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -23163,7 +23148,6 @@
     { "name": "chanoyu-gakkai.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "chaos.run", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "chaospott.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "chaouby.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "charbonnel.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "charles-darwin.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "charlestonfacialplastic.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -24036,7 +24020,6 @@
     { "name": "hulsoft.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "human-clone.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "humanenrich.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "humans.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "humanzee.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "humblebee.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "humblebee.foundation", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -24239,7 +24222,6 @@
     { "name": "jrtapsell.co.uk", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "jslidong.top", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "juan23.edu.uy", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "juanmaguitar.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "juergen-elbert.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "juka.pp.ua", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "julegoerke.de", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -26161,7 +26143,6 @@
     { "name": "888lu.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "100-downloads.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "5533445.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "33445.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "8888av.co", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "0xdc.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "023sec.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -29727,7 +29708,6 @@
     { "name": "bonaccorso.eu", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "boueki.jp", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "booox.pw", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "bodsch.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "biomodra.cz", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "breadandlife.org", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "bitroll.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -31843,7 +31823,6 @@
     { "name": "fr0zenbits.io", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "frugalfamilyhome.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "gallicrooster.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
-    { "name": "geaskb.nl", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "geleia-real.com", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "giftmaniabrilhos.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
     { "name": "globalprojetores.com.br", "policy": "bulk-18-weeks", "mode": "force-https", "include_subdomains": true },
@@ -38373,7 +38352,6 @@
     { "name": "america.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ameriikanpoijat.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "amielucha.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "amitpatra.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ammanagingdirectors.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "amosng.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "andariegocusco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -39463,7 +39441,6 @@
     { "name": "passvanille-reservation.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "patentados.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "patika-biztositas.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "pay.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pcdocjim.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "peaceispossible.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pearlcohen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -39807,7 +39784,6 @@
     { "name": "trade-arcade.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "travel1x1.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "travellovers.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "treaslockbox.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "treetopsecurity.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tribly.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "troomcafe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -40552,7 +40528,6 @@
     { "name": "pbcomp.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pdxtowncar.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "peaceloveandlabor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "pedikura-vitu.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pelletizermill.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pendriveapps.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pengumuman.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -43036,7 +43011,6 @@
     { "name": "roundaboutweb.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ruquay.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "salvaalocombia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "schmelle.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "scpslgame.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "securitysense.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "see.wtf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -43140,7 +43114,6 @@
     { "name": "xy7373.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ycherbonnel.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yh35.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "yigujin.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "youareme.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "younl.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "your-erotic-stories.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -43803,7 +43776,6 @@
     { "name": "wichitafoundationpros.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wirkaufendeinau.to", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wlwlwx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "wow-screenshots.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ws-meca.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wsadek.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "www-9822.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -44307,7 +44279,6 @@
     { "name": "nibo.blog", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nicsezcheckfbi.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "niffler.software", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ninjio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nodecraft.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "noelclaremont.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "noleggio-bagni-chimici.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -44841,7 +44812,6 @@
     { "name": "vapensiero.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vda.li", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wateroutlook.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "wayfair.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "webministeriet.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "webnames.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "werkz.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -44972,7 +44942,6 @@
     { "name": "inchenaim.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "indexyz.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "industriasrenova.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "international-nash-day.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ioliver.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ipadkaitori.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "itesign.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -48070,7 +48039,6 @@
     { "name": "outdoorlightingwestlakevillage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ovelhaostra.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "overamsteluitgevers.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "oxygin.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pablofain.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pacificpalisadeselectric.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pacificpalisadeselectrician.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -49519,7 +49487,6 @@
     { "name": "woltlab-demo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "woofsbakery.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "woomai.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "workoptions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "worldmeteo.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "worldofarganoil.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wpsitemovers.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -49549,7 +49516,6 @@
     { "name": "zander.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zenchain.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zentiweb.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "zhengouwu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zhimajk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zhthings.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zlaty-tyden.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -49609,7 +49575,6 @@
     { "name": "cashbook.co.tz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "catchhimandkeephim.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "catl.st", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ccavenue.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cccwien.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ceoptique.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ch47f.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -50412,7 +50377,6 @@
     { "name": "hti.digital", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hubapi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hubspot.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "huffsinsurance.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "huskyeye.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hydrosight.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "hyparia.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -51987,7 +51951,6 @@
     { "name": "neteraser.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nethostingtalk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nex.li", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "nl3ehv.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "notarkrauss.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nulap.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nxit.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -53522,7 +53485,6 @@
     { "name": "hysh.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "iaminashittymood.today", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ianvisits.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ibe.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "iblackfriday.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "icetiger.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "idesoft.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -53549,7 +53511,6 @@
     { "name": "isavings.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "iskanderbroere.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "islavolcan.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "itspecialista.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "itsundef.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "iurisnow.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ivy-league-colleges.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -55307,7 +55268,6 @@
     { "name": "ebenvloedaanleggen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "echobridgepartners.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "echtes-hutzelbrot.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "echtgeld-casinos.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "eclanet.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ecliptic.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "edi-gate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -56064,7 +56024,6 @@
     { "name": "westernpadermatologist.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "westside-pediatrics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "weswitch4u.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "wettanbieter-vergleich.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wewin88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wewin88.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wheresbuzz.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -57075,7 +57034,6 @@
     { "name": "naturalezafengshui.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "natverkstekniker.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "naughtytoy.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "naut.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "navstivime.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ndum.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nederland.media", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -59837,7 +59795,6 @@
     { "name": "olivier-rochet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "omegarazer.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "onehost.blue", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "online-biblio.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "onlinecasinoselite.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "opcionpublicitaria.pe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "open-ctp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -59949,7 +59906,6 @@
     { "name": "reddingsbrigadeveghel.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "regensburg-repariert.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "remembermidi.sytes.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "rena.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "resdon.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "respons.je", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "respons.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -60078,7 +60034,6 @@
     { "name": "sunbury.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sunhaoxiang.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sunplay.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "supplementswatch.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sustc.ac.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sv-schody.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sweepy.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -62409,7 +62364,6 @@
     { "name": "q1000.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "qualitywaterproofing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ranobe.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "rapidminer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "rawcode.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "rawpearls.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "rdactive.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -63161,7 +63115,6 @@
     { "name": "l0v0l.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lambertz.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lapatio.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "lauraohagan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "laurineprice.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lawabidingcactus.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "leiyinan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -63374,7 +63327,6 @@
     { "name": "bestladyshaver.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "betrifft-mich-dsgvo.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bi1gif.radio", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "bigadcompany.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "biosalts.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bongloy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bonus.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -63510,7 +63462,6 @@
     { "name": "lsh1688.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lucasit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "magicbeanschool.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "marioberluchi.by", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "marjorie-wiki.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "market-vanna.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "markshroyer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -63699,7 +63650,6 @@
     { "name": "attiremr.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "autorijschooljohanbos.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "available.direct", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "badgr.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bakerviewdentalcentre.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "banka.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "barcelonabagels.cat", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -65720,7 +65670,6 @@
     { "name": "arilto.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "arkhvoid.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "auburn-housekeeper.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "badgr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bagnichimici.milano.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bargainsettelement.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "baron14.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -68827,7 +68776,6 @@
     { "name": "btt1212.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "btt2020.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "btt2121.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "btt256.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "btt381g.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "btt686.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "btt8.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -69183,7 +69131,6 @@
     { "name": "rr6957.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "rssl.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "russelljohn.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "rylandgoldman.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "s6729.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "s6729.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "s6957.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -69984,7 +69931,6 @@
     { "name": "idealize.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ilc666.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ime-a-tolerancia-eredmenye.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "imediamyanmar.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "imediasingapore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "immivest.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "inboxceo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -70664,7 +70610,6 @@
     { "name": "ag6211.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ag88110.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ag88220.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ag88799.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "agyacht.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ai-media.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "aj-foster.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -70753,7 +70698,6 @@
     { "name": "ebteam.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ecalculator.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "edcaptain.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "eet.nu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "eikentafels.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "eisblau.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "elldus.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -71711,7 +71655,6 @@
     { "name": "boxtreeclinic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "brickadia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "btopc.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "btt6262a.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "buysoft.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "byfeldt.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cadastroloteamento.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -71787,7 +71730,6 @@
     { "name": "fb.gg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fgsv-heureka.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "filedesc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "fireflyiii.spdns.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "firerain.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "firmajulegaver.dk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fite.family", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -73259,9 +73201,6 @@
     { "name": "918bip.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "918bis.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "918bit.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "918ddo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "918ddx.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "918ffa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "918nn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "918ze.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "91d91.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -73625,7 +73564,6 @@
     { "name": "btt0505.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "btt0606.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "btt11.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "btt216.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "btt583g.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "btt7878.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "btt829.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -73633,7 +73571,6 @@
     { "name": "btt889g.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "btt918958.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "btta16.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "btta26.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "buddy-acceptance-authentication-api.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "buddy-acceptance-profiles-api.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "buddy-acceptance-users-api.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -75039,7 +74976,6 @@
     { "name": "t88hh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "t88kk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "t88ll.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t88rr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "t88uu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "t88ww.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "t88yy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -76181,7 +76117,6 @@
     { "name": "lierohell.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "life-in-hell.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lightsfromspace.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "lilai107.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lilai18.ph", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lilai634.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "limstash.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -76203,7 +76138,6 @@
     { "name": "livejh.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "livetopknigi.gq", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "livfcshop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "lldy88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "localtownhouses.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "logicdream.tk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lojadkstore.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -77951,7 +77885,6 @@
     { "name": "eznetworks.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "f8036.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "f81818.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "fbe.to", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ff18.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fh169.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "finotax.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -78329,7 +78262,6 @@
     { "name": "bastide-viens.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "berksarl.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bestcomputersecuritybooks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "beyondboxgifts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bhthome.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "biftin.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "binaries.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -78527,7 +78459,6 @@
     { "name": "obu4alka.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "oe2018.gov.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "oe2019.gov.pt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "onlinekocunuz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "only.sh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ontourmarketing.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ontrio.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -78918,7 +78849,6 @@
     { "name": "raveboy.dyndns.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "raydius.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "reeves-family.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "renedekoeijer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "rheijmans.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ribella.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "richieheijmans.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -79325,7 +79255,6 @@
     { "name": "sevipro.mx", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "shakthifacility.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "siamericas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "sianipestcontrolinc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "simplysmartgardening.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "sipstix.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "skaginn.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -79801,7 +79730,6 @@
     { "name": "caycehouse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "cbnainital.org.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ccli.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "centralhealthplan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "centrumpieknairelaksu.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "chartsheets.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "chiavistello.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -79840,7 +79768,6 @@
     { "name": "drsheri.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ea-lateleassistance.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "eaglemoe.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "easypets.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ecotechnologyti.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "elprint.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "emeraldislerealty.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -79885,7 +79812,6 @@
     { "name": "justin-p.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kb702.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kb7474.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "kb88dc28.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kilbi-reussbuehl.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kingdominnergy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "kingshome.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -79903,7 +79829,6 @@
     { "name": "kstr.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lacochinacounselor.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lacocina.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "landsbankinn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lederkleren.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "leoservicosetc.store", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "leruevintage.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -79915,7 +79840,6 @@
     { "name": "lorenzocampagna.myqnapcloud.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ltcwaterwijk.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "macaos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "madeinolive.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "magniflood.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mangabank.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mansora.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -79959,7 +79883,6 @@
     { "name": "parkeerbordenhuren.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "paroisses-theix-surzur.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pcdbank.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "pfonks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "piektraining.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "pitoufi.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "planisys.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -81450,7 +81373,6 @@
     { "name": "fam-borsch.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fantasticcleanersbristol.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fastighetsekonomi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "ferc.gov", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fetishbazar.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ff00228.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "fffinfo.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -84909,7 +84831,6 @@
     { "name": "daie-inc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dailychristianpodcast.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dailyrenewblog.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "danndorf.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "davidgroup.co.id", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "davidops.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "dcave.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -86265,7 +86186,6 @@
     { "name": "wijnlandkroatie.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wpcc.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wwmm.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xebeche.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xin-in.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xin-in.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xing-in.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -86762,7 +86682,6 @@
     { "name": "mijam.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mijnkantoor.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mikedhoore.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "milkkids.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "minibaggerverleih-aulendorf.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "missmaid.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "missmaid.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -87506,7 +87425,6 @@
     { "name": "mau.chat", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "mau.life", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "maxiglobal.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "mczone.su", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "meekhak.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "meinephbern.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "meldpuntemma.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -87536,7 +87454,6 @@
     { "name": "niederalt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nlc.org.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nopaincenter.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "npu.best", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nunu.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "o81365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "o82365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -88088,7 +88005,6 @@
     { "name": "lermer.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "levante.net.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "libreho.st", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "lightwitch.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lintelliftdks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "loukas-stoltz.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "lucklesslovelocks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -88142,7 +88058,6 @@
     { "name": "neverguess.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "newcontext.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nhglobalpartners.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "nixval.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nordlocker.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nordpass.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "nordsec.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -89916,22 +89831,15 @@
     { "name": "3651203.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "3651204.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "3651205.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "365123456.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "3653650000.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "3653651111.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "3653653333.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "3653654444.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "3655053.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "51cls.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "616578.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "616728.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "616758.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "616798.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "666648.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "6upagent.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "76678.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "878989.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "96678.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "a1demolitionhauling.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "a66.la", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "a6619.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -89974,7 +89882,6 @@
     { "name": "arminsure.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "avgindiantech.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "avhwelding.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "b538.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "b5901.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "b5902.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "b5903.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -89984,8 +89891,6 @@
     { "name": "b5907.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "b5908.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "b5910.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "b6530.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "b6531.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "barkstop.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "basedos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "bayer.earth", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -90085,7 +89990,6 @@
     { "name": "howtorunfasterandlonger.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "humitat-stop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "huntyourshitaround.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "i36588.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "i7.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ilab.health", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "iletisimmakinesi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -90328,21 +90232,6 @@
     { "name": "x59788.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "x59888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "x59988.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "x7713.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "x7719.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "x7782.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "x7785.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "x7795.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "x77dd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "x77hh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "x77jj.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "x77kk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "x77mm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "x77nn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "x77pp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "x77qq.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "x77tt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "x77ww.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "x98d.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "x98e.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "x98f.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -90371,29 +90260,9 @@
     { "name": "xpj000555.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xpj000666.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xpj678678.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xpj909.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xpj909.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xpj909.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xpj909.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xpj909.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xpj919.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xpj919.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xpj919.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xpjab.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xpjbeting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xpjce.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "xpjcs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xpjcu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xpjdi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xpjei.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xpjfan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xpjmd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xpjtop.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xpjwa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xpjwb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xpjwc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "xpjwd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "y365188.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yellsy.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yourbusinesscommunity.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "yourdomain.host", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -90423,7 +90292,6 @@
     { "name": "0117552.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "0127552.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "0137552.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "0319z6.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "1004233.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "111ttt.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "1me.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -90461,7 +90329,6 @@
     { "name": "7552011.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "7552012.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "7552013.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "aa4888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "abcorporate-aviation.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "abcorporate-aviation.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "adventurealpinetreks.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -90499,9 +90366,6 @@
     { "name": "b89cc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "b89dd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "b89ee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "b89ff.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "b89gg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "b89hh.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "b89ii.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "b89jj.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "backtheeffup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -90904,27 +90768,6 @@
     { "name": "symeonchen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "systemnik.store", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "szotkowski.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t8803.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t8805.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t8807.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t8809.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t8815.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t8817.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t8819.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t8830.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t88jj.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t88mm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t88nn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t88oo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t88ss.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t88vip0.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t88vip1.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t88vip2.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t88vip3.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t88vip4.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t88vip5.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t88vip6.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "t88vip7.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "talkaboutdesign.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tandakutip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tauran.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -90954,19 +90797,6 @@
     { "name": "transfurrmation.town", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "tripsweet.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "truyenfull.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "tt0766.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "tt0966.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "tt2866.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "tt3699.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "tt3766.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "tt3999.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "tt7199.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "tt7299.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "tt7399.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "tt8166.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "tt8266.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "tt8366.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "tt9799.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "turm-umzuege.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ua-blacklist.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "ucb.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -90991,27 +90821,9 @@
     { "name": "vokieciupamokos.lt", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vonpawn.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "vschafer.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "w000999.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "w123123.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "w234234.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "w456456.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "w555.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "w567567.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "w666.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "w66w66.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "w678678.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "w789789.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "w81519.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "w888011.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "w888022.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "w888033.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "w888044.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "w888055.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "w888066.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "w888077.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "w888088.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "w888099.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
-    { "name": "w99w99.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wallisdiervoeding.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "webtrees.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "wercat.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
@@ -91046,6 +90858,638 @@
     { "name": "zoftbaby.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zusterjansen.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     { "name": "zwilla.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "11ag8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "123viajando.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "12ag8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "13ag8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "16ag6.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "1abcicka.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "22ag6.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "345678365.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "365.systems", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "36ag8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "4pillarsit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "567667.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "61ag8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "66ag9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "72hours2sold.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "87ag9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "8ag8.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "93ag8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "abetterdeath.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "abi95oha.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "abrah.am", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "academie-essentiel.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "adventus.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "afharvey.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag000.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag01.la", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag011.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag018.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag022.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag06.la", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag066.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag08.la", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag09.la", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag11.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag123.la", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag130.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag138.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag13842.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag1386.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag155.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag158.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag1601.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag1603.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag1604.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag1607.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag166.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag271.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag2722.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag2786.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag285.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag2855.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag288.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag2886.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag2897.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag2978.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag3.la", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag3115.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag3117.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag3119.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag33.la", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag388.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag3916.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag3917.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag393.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag3953.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5152.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5159.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5326.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5358.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5392.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5519.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag556.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5623.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5657.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5662.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5758.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5761.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5852.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5856.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5862.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5876.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5917.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5933.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5936.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5939.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5951.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5952.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag5967.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6.im", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6.pub", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6.vc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag600.la", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag618.la", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6272.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6283.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6291.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6298.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag66567.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag666.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag66668.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6675.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6676.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6819.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6825.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag69000.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag6995.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag7.la", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag72.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag7273.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag77.la", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag77.win", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag77655.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag7811.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag7822.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag8.im", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag8.live", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag8.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag8.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag806.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81117.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81119.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81122.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81125.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81163.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81191.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag812.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag812.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81211.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81213.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81215.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81268.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81275.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81277.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81279.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81325.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81362.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81393.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81399.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81568.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag816.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81611.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81613.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag818.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag818.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81879.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81881.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81886.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag819.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81912.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81917.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81933.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag81939.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag82001.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag82006.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag82007.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag82008.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag82011.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag82015.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag82018.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag82018.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag82022.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag821.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag82135.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag8218.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag822.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag82225.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag82226.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag82287.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag8400.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag8500.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag860.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag8600.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag865.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag8778.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag880.win", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag891.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag898.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag899.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag89951.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag8vip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag9.im", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag9.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag9005.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag905.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag908.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag9100.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag918.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag918.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag918.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag92018.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag9532.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag955.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag96.win", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag961.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag9621.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag9623.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag966.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag9792.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag9793.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag98.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag9800.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag9815.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag983.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag992.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag9931.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag995.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag9973.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ag9vip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agg097.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agg66.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agg77.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agg88.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agsogou.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agsun6.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agvip1000.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agvip1888.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agvip2001.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agvip2008.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agvip2013.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "agvip986.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aiden.cool", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aiwansky.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "akay.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "algoritmususpechu.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "amberwiz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "anamelikian.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "apadmi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ararrl.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ararrl.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "artj.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "astrobriga.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "autosalesmachine.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "avanpost.co", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "avivamiento-radio.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "aztv.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ballettstudio-ost.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bastardandpoors.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bech32.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "benpfitzner.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "big-office.lviv.ua", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "blindsjoburg.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "boschveldtuin.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "brunolt.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bulutkey.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bundesverband-krisenintervention.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "bundesverbandkrisenintervention.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "callanjg.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "callqa.center", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "caodo.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "carespan.clinic", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "casamentos.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ccsae.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ceska-polygraficka.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "checktech.group", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "childhr.org.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chizipoms.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "chriscampdesigns.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "christian-oette.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cichlid-world.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cjpsrilanka.lk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "clubon.com.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "combustibilaspen.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "commercialcleaningbrisbane.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "concetrabajos.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "consulenzanobiliare.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cranenburgh.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cranioo.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "crestasantos.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "crowdstack.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cubeo.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "cyclowiz.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "d64.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dannyrohde.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "datenschutz-gruenwald.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "datenschutz-isny.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "datenschutz-leutkirch.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "datenschutz-oberschwaben.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "datenschutz-ravensburg.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "datenschutz-wangen.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "datenschutz-weingarten.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dautuvang.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "daysgolfclub.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dealsale.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "defamiliehagen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "delicon.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "deyanadeco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dienmayplus.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dietlein.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "diffuzehr.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "disinfestazioni-sardegna.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dmilb.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dogwalkeru.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dotcomtest02-single.azurewebsites.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "drastik.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "drivenbyperspective.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "droidee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dubaire.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dusty.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dutchassistancedogs.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "dys-coaching.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "e-m1.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eggendorfer.at", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eggendorfer.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eggendorfer.biz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eggendorfer.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eggendorfer.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eggendorfer.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eggendorfer.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eggendorfer.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eggendorfer.li", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eggendorfer.name", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eggendorfer.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eggendorfer.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eggendorfer.pro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eggendorfer.rocks", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eggendorfer.tv", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eggendorfer.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eggendorfer.us", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eggendorfer.wine", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "elettricista.roma.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "elfuerteclamor.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "emby.live", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "emsliespharmacy.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "encanttemais.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "encontroespiritadeinverno.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "engione.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "enthasso.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "entrup.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "eperniagaan.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ergaomnes.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "erictgilmour.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "estallidodigital.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ethicalescorts.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "evergarden.cn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "expanda.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "faked.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fallout-craft.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "familie-mueller.com.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fan8hd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ffp-survey.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fh14.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "filli-it.ch", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "flashcrasher.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "floating-journey-64892.herokuapp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "flugschule-usa.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "free8hd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "freewillfilm.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ftrac.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fudubank.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "furukogarasusha.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fusionapps.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "fusionapps.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "galleoncloud.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gamanlu.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "geekobyte.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "genbars.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "genometrik.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "glutenfreeandtasty.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gmcbm.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gon45.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "googlepinyin.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "gozadera.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "greatnetsolutions.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "halovanic.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hangarbox.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "happynewyear2020countdown.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hawaiiforbernie.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "heinenhopman.ro", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hispania-valencia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "honeyspot.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hooghiemstrazelf.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hostedghost.eu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hostedghost.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "hostedghost.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "house-scape.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "humansense.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "huuduc.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "i-connect.ie", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "iblowdry.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ideamiapublicidad.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ilfumoshop.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "immedicohospitalario.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "infra.beer", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "infraget.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "insuremyworkcomp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "isab.top", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "iskconnews.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ivan1874.dynu.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jakobs.systems", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jb0.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jfvaccountants.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jimkimmel.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jmisern.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jnssnfotografie.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "jordandirections.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "joseluishenriquez.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k811111.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k8cf002.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k8cf003.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k8cf005.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k8cf006.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k8cf007.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k8top.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k8vn001.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k8vn002.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k8vn003.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k8vn005.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k8vn006.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k8vn007.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k8vn008.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k8vn009.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k8vn010.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k8vn011.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "k8vn9999.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kaiva.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kalhufvudet.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kangutingo.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kathy.best", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "keeley.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "keesslop.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kpnthings.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kreuzwortraetsellosungen.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "krisenintervention-deutschland.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "kriseninterventiondeutschland.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ks7.vip", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lagrange.cloud", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lakorntoday.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "largeandhighquality.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lawyermidrand.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lebalcondesraspes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "leon.wtf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "librairiezbookstore.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lidl-vins.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "linguatrip.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lipaslovanska.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "liulo.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "liverobot8.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "loonbedrijfdenboer.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lowratelocksmith.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lsc.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lubersacr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "lucorautopartes.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "m3e30.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "madix.cl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mailgun.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mailmaid.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mandarinpediatrics.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "manuelraimo.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "markfisher.photo", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "markoglou.com.gr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "massageandwellbeing.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "maybeonline.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mccordscvs.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mcvs.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "medicaltools.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "medictools.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "medunovi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "megasupportcr.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "meilleursjeuxporno.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mempool.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mens-v.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "milkagyengedseg.hu", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "milkandbourbons.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "missionpuppy.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mmichaelb.pw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "montrain.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "moove-it.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mountknowledge.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "moving-target.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mycloudsaas.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "mycrowdstack.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nedermisp.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nejmaklerka.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nintendohill.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "normapro.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "nully.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "okayloser.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ontopoflove.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "opticsboss.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "overlord.network", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pack.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "palessit.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pcf-frankfurt.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pipscprd.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "poirierlavoie.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pojdnafp.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "pomdoc.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "poquiloco.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "private-diary-taka.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "prodigyhq.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "projecttools.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "promoglisse.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "puredns.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "r3t.io", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rabbit.finance", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ramdigital.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "randstalker.ovh", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "realm-of-shade.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rellmusic.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "repairit.support", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "restaurant-eatenjoy.be", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "retinacv.es", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "riho.moe", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rimo.site", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "roar.com.br", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "robbinsgaragedoorwenatchee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ronbyrne.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rscturmoil.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "rubenpeeters.ml", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "saint-sym.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sanates.cz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sapuseven.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "scag9.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "securesense.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "semesur.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "seminarraum-isny.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sequachee.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "shipito.kg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "shipmonk.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "shippinglabel.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "shishadenbosch.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "smlk.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "softskills.tech", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "soleil.space", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "soma.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "soninger.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "standheizung-shop.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "steno.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stephengeorge.co.uk", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stevenkendypierre.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stjohncamden.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "stmsouthcoventry.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "striata.mobi", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "striata.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sudosaveclimate.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "superhappyfun.club", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "sydneyexperiences.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "systemofabrown.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "szotkowski.online", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "t-unit.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tactical.zone", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tallgrasslegal.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "taxedesejour-airbnb.fr", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "teallhaycock.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tecnopiniones.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "teplo-unit.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tferdinand.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tgtw.cc", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "the-azad.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thehoff.ddnss.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "themegteam.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "thirdwaverevenue.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tinf.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tkmr-gyouseishosi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tld.gg", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tmhanoi.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tobiase.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tonalaw.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "topicalnet.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "topophile.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "torremarsalou.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "trungvien.vn", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "tudienchinhta.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "u9yy.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "ufacesign.in", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "up-stage.info", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "up-stage.jp", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "upakweship.ca", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "urbanemc.net", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "usawireguard.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "uzay.org", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vanuithartenziel.nl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vg-store.ir", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vizedia.ga", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "vleo.me", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "volcano-ug.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "volcano-x.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "volcano75.ru", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wagnergroup.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wcscmp.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "we8hd.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "websitelia.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wetravel.company", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wikilinux.xyz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wildfoxlady.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wippie.se", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wiseradiology.com.au", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wmccancercenter.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wnuq.best", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wofox.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wordpressarequipa.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "wrong.wang", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "www.gov.pl", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xinyitour.tw", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn----7sbbagp2bcfwdeee1afm.xn--p1ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn----dtbhcpoeofgcvoic1s.xn--p1ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--c1aehtaetb.xn--p1ai", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xn--pascal-klsch-cjb.de", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xoan.cf", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xotictrends.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xtom.support", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "xyj22.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yachtcita.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yalacoins.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yatai18.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yayou.ag", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yn.org.nz", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yokoda.okinawa", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yt220.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yt605.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yt606.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yt629.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yt653.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yt656.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yt675.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yt818.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yt835.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yt839.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yt881.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yt892.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yt962.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "yt972.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zenown.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zidanpainting.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zumtaedanceschool.co.za", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zupit.it", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
+    { "name": "zz772.com", "policy": "bulk-1-year", "mode": "force-https", "include_subdomains": true },
     // END OF 1-YEAR BULK HSTS ENTRIES
 
     // Only eTLD+1 domains can be submitted automatically to hstspreload.org,
diff --git a/net/trust_tokens/BUILD.gn b/net/trust_tokens/BUILD.gn
index 9aec1d17..bdc97d0 100644
--- a/net/trust_tokens/BUILD.gn
+++ b/net/trust_tokens/BUILD.gn
@@ -6,13 +6,12 @@
 
 source_set("trust_tokens") {
   visibility = [
-    "//net",
-    "//services/network",
     ":tests",
+    "//net/*",
+    "//services/network/",
   ]
 
-  # TODO(davidvc): Public API to be added in a subsequent CL.
-  public = []
+  public = [ "trust_token_store.h" ]
 
   friend = [ ":tests" ]
 
@@ -20,26 +19,35 @@
     "in_memory_trust_token_persister.cc",
     "in_memory_trust_token_persister.h",
     "trust_token_persister.h",
+    "trust_token_store.cc",
+    "types.cc",
+    "types.h",
   ]
 
   deps = [
-    ":public_proto",
     ":storage_proto",
     "//base",
     "//url",
   ]
+
+  public_deps = [ ":public_proto" ]
 }
 
 source_set("tests") {
   testonly = true
 
-  sources = [ "trust_token_persister_unittest.cc" ]
+  sources = [
+    "trust_token_persister_unittest.cc",
+    "trust_token_store_unittest.cc",
+    "types_unittest.cc",
+  ]
 
   deps = [
     ":public_proto",
     ":storage_proto",
     ":trust_tokens",
     "//base",
+    "//base/test:test_support",
     "//testing/gmock",
     "//testing/gtest",
     "//url",
diff --git a/net/trust_tokens/OWNERS b/net/trust_tokens/OWNERS
new file mode 100644
index 0000000..53f0470
--- /dev/null
+++ b/net/trust_tokens/OWNERS
@@ -0,0 +1,3 @@
+csharrison@chromium.org
+svaldez@chromium.org
+asanka@chromium.org
diff --git a/net/trust_tokens/proto/public.proto b/net/trust_tokens/proto/public.proto
index 1d99729..5700635 100644
--- a/net/trust_tokens/proto/public.proto
+++ b/net/trust_tokens/proto/public.proto
@@ -8,13 +8,14 @@
 
 option optimize_for = LITE_RUNTIME;
 
-// A TrustTokenCommitmentKey message represents a single commitment key received
-// from an issuer’s key commitments endpoint.
-message TrustTokenCommitmentKey {
-  // The body of the keys. Used for comparison (when checking if
+// A TrustTokenKeyCommitment message stores a single key received
+// from an issuer’s key commitments endpoint, along with associated
+// metadata.
+message TrustTokenKeyCommitment {
+  // The key's body. Used for comparison (when checking if
   // stored tokens’ keys are still current) and, by BoringSSL, for
   // cryptographic operations.
-  optional bytes body = 1;  // required
+  optional bytes key = 1;  // required
 
   // The expiry time of the key.
   // (Here and elsewhere, string times are serialized base::Times
@@ -36,7 +37,7 @@
   // The key with which the Token was signed. Tokens
   // are only provided to servers while their commitment keys
   // remain active.
-  optional bytes commitment_key_body = 2;  // required
+  optional bytes signing_key = 2;  // required
 }
 
 // A SignedTrustTokenRedemptionRecord message stores state associated with a
@@ -46,8 +47,9 @@
 // with the SRR.
 message SignedTrustTokenRedemptionRecord {
   // The body of an SRR encodes information such as its top-level
-  // origin and its expiration time, but Chrome doesn’t control
-  // the encoding and uses a library to extract these values.
+  // origin and its expiration time. The encoding is opaque to //net; BoringSSL
+  // provides interfaces to read data from the body that is pertinent to
+  // protocol execution.
   optional bytes body = 1;
   // If one of public_key or signing_key is present, the other must also be
   // present.
diff --git a/net/trust_tokens/proto/storage.proto b/net/trust_tokens/proto/storage.proto
index adeb5286..fbf8360 100644
--- a/net/trust_tokens/proto/storage.proto
+++ b/net/trust_tokens/proto/storage.proto
@@ -10,7 +10,7 @@
 
 import "public.proto";
 
-// An TrustTokenIssuerConfig message represents persistent state scoped
+// A TrustTokenIssuerConfig message represents persistent state scoped
 // to a single Trust Tokens issuer origin.
 // An issuer’s config contains:
 // - any signed-but-unspent tokens received from the issuer; and
@@ -18,8 +18,8 @@
 // per issuance request), if it has configured one via its key
 // commitment endpoint.
 message TrustTokenIssuerConfig {
-  // Keys the issuer has recently committed (we don’t need to store stale keys)
-  repeated TrustTokenCommitmentKey keys = 1;
+  // Keys the issuer has recently committed (no need to store stale keys)
+  repeated TrustTokenKeyCommitment keys = 1;
   optional int32 batch_size = 2;
   repeated TrustToken tokens = 3;
   // The time of the most recent issuance for this pair. Used for
diff --git a/net/trust_tokens/trust_token_store.cc b/net/trust_tokens/trust_token_store.cc
new file mode 100644
index 0000000..cba7772
--- /dev/null
+++ b/net/trust_tokens/trust_token_store.cc
@@ -0,0 +1,312 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/trust_tokens/trust_token_store.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/optional.h"
+#include "net/trust_tokens/proto/public.pb.h"
+#include "net/trust_tokens/proto/storage.pb.h"
+#include "net/trust_tokens/types.h"
+#include "third_party/protobuf/src/google/protobuf/repeated_field.h"
+
+namespace net {
+
+namespace {
+// Until the underlying BoringSSL functionality is implemented to extract
+// expiry timestamps from Signed Redemption Record bodies, default to
+// never expiring stored SRRs.
+class NeverExpiringExpiryDelegate
+    : public TrustTokenStore::RecordExpiryDelegate {
+ public:
+  bool IsRecordExpired(
+      const SignedTrustTokenRedemptionRecord& record) override {
+    return false;
+  }
+};
+}  // namespace
+
+TrustTokenStore::TrustTokenStore(std::unique_ptr<TrustTokenPersister> persister)
+    : TrustTokenStore(std::move(persister),
+                      std::make_unique<NeverExpiringExpiryDelegate>()) {}
+
+TrustTokenStore::TrustTokenStore(
+    std::unique_ptr<TrustTokenPersister> persister,
+    std::unique_ptr<RecordExpiryDelegate> expiry_delegate_for_testing)
+    : persister_(std::move(persister)),
+      record_expiry_delegate_(std::move(expiry_delegate_for_testing)) {
+  DCHECK(persister_);
+}
+
+TrustTokenStore::~TrustTokenStore() = default;
+
+void TrustTokenStore::RecordIssuance(const url::Origin& issuer) {
+  DCHECK(!issuer.opaque());
+  url::Origin issuer_origin = issuer;
+  std::unique_ptr<TrustTokenIssuerConfig> config =
+      persister_->GetIssuerConfig(issuer);
+  if (!config)
+    config = std::make_unique<TrustTokenIssuerConfig>();
+  config->set_last_issuance(internal::TimeToString(base::Time::Now()));
+  persister_->SetIssuerConfig(issuer, std::move(config));
+}
+
+base::Optional<base::TimeDelta> TrustTokenStore::TimeSinceLastIssuance(
+    const url::Origin& issuer) {
+  DCHECK(!issuer.opaque());
+  std::unique_ptr<TrustTokenIssuerConfig> config =
+      persister_->GetIssuerConfig(issuer);
+  if (!config)
+    return base::nullopt;
+  if (!config->has_last_issuance())
+    return base::nullopt;
+  base::Optional<base::Time> maybe_last_issuance =
+      internal::StringToTime(config->last_issuance());
+  if (!maybe_last_issuance)
+    return base::nullopt;
+
+  base::TimeDelta ret = base::Time::Now() - *maybe_last_issuance;
+  if (ret < base::TimeDelta())
+    return base::nullopt;
+
+  return ret;
+}
+
+void TrustTokenStore::RecordRedemption(const url::Origin& issuer,
+                                       const url::Origin& top_level) {
+  DCHECK(!issuer.opaque());
+  DCHECK(!top_level.opaque());
+  std::unique_ptr<TrustTokenIssuerToplevelPairConfig> config =
+      persister_->GetIssuerToplevelPairConfig(issuer, top_level);
+  if (!config)
+    config = std::make_unique<TrustTokenIssuerToplevelPairConfig>();
+  config->set_last_redemption(internal::TimeToString(base::Time::Now()));
+  persister_->SetIssuerToplevelPairConfig(issuer, top_level, std::move(config));
+}
+
+base::Optional<base::TimeDelta> TrustTokenStore::TimeSinceLastRedemption(
+    const url::Origin& issuer,
+    const url::Origin& top_level) {
+  DCHECK(!issuer.opaque());
+  DCHECK(!top_level.opaque());
+  auto config = persister_->GetIssuerToplevelPairConfig(issuer, top_level);
+  if (!config)
+    return base::nullopt;
+  if (!config->has_last_redemption())
+    return base::nullopt;
+  base::Optional<base::Time> maybe_last_redemption =
+      internal::StringToTime(config->last_redemption());
+  // internal::StringToTime can fail in the case of data corruption (or writer
+  // error).
+  if (!maybe_last_redemption)
+    return base::nullopt;
+
+  base::TimeDelta ret = base::Time::Now() - *maybe_last_redemption;
+  if (ret < base::TimeDelta())
+    return base::nullopt;
+  return ret;
+}
+
+bool TrustTokenStore::IsAssociated(const url::Origin& issuer,
+                                   const url::Origin& top_level) {
+  DCHECK(!issuer.opaque());
+  DCHECK(!top_level.opaque());
+  std::unique_ptr<TrustTokenToplevelConfig> config =
+      persister_->GetToplevelConfig(top_level);
+  if (!config)
+    return false;
+  return base::Contains(config->associated_issuers(), issuer.Serialize());
+}
+
+void TrustTokenStore::SetAssociation(const url::Origin& issuer,
+                                     const url::Origin& top_level) {
+  DCHECK(!issuer.opaque());
+  DCHECK(!top_level.opaque());
+  std::unique_ptr<TrustTokenToplevelConfig> config =
+      persister_->GetToplevelConfig(top_level);
+  if (!config)
+    config = std::make_unique<TrustTokenToplevelConfig>();
+  auto string_issuer = issuer.Serialize();
+  if (!base::Contains(config->associated_issuers(), string_issuer)) {
+    config->add_associated_issuers(std::move(string_issuer));
+    persister_->SetToplevelConfig(top_level, std::move(config));
+  }
+}
+
+std::vector<TrustTokenKeyCommitment> TrustTokenStore::KeyCommitments(
+    const url::Origin& issuer) {
+  DCHECK(!issuer.opaque());
+  std::unique_ptr<TrustTokenIssuerConfig> config =
+      persister_->GetIssuerConfig(issuer);
+
+  if (!config)
+    return std::vector<TrustTokenKeyCommitment>();
+
+  return std::vector<TrustTokenKeyCommitment>(config->keys().begin(),
+                                              config->keys().end());
+}
+
+void TrustTokenStore::SetKeyCommitmentsAndPruneStaleState(
+    const url::Origin& issuer,
+    base::span<const TrustTokenKeyCommitment> keys) {
+  DCHECK(!issuer.opaque());
+  DCHECK([&keys]() {
+    std::set<base::StringPiece> unique_keys;
+    for (const auto& key : keys)
+      unique_keys.insert(base::StringPiece(key.key()));
+    return unique_keys.size() == keys.size();
+  }());
+
+  std::unique_ptr<TrustTokenIssuerConfig> config =
+      persister_->GetIssuerConfig(issuer);
+  if (!config)
+    config = std::make_unique<TrustTokenIssuerConfig>();
+
+  // Because of the characteristics of the protocol, this will be
+  // quite small (~3 elements).
+  google::protobuf::RepeatedPtrField<TrustTokenKeyCommitment> keys_to_add(
+      keys.begin(), keys.end());
+
+  for (TrustTokenKeyCommitment& new_key : keys_to_add) {
+    for (const TrustTokenKeyCommitment& existing_key : config->keys()) {
+      if (existing_key.key() == new_key.key()) {
+        // It's safe to break here because of the precondition that
+        // the commitments in |keys_to_add| have distinct keys.
+        *new_key.mutable_first_seen_at() = existing_key.first_seen_at();
+        break;
+      }
+    }
+  }
+
+  config->mutable_keys()->Swap(&keys_to_add);
+
+  google::protobuf::RepeatedPtrField<TrustToken> filtered_tokens;
+  for (auto& token : *config->mutable_tokens()) {
+    if (std::any_of(config->keys().begin(), config->keys().end(),
+                    [&token](const TrustTokenKeyCommitment& key) {
+                      return key.key() == token.signing_key();
+                    }))
+      *filtered_tokens.Add() = std::move(token);
+  }
+
+  config->mutable_tokens()->Swap(&filtered_tokens);
+
+  persister_->SetIssuerConfig(issuer, std::move(config));
+}
+
+void TrustTokenStore::SetBatchSize(const url::Origin& issuer, int batch_size) {
+  DCHECK(!issuer.opaque());
+  DCHECK(batch_size > 0);
+  std::unique_ptr<TrustTokenIssuerConfig> config =
+      persister_->GetIssuerConfig(issuer);
+  if (!config)
+    config = std::make_unique<TrustTokenIssuerConfig>();
+  config->set_batch_size(batch_size);
+  persister_->SetIssuerConfig(issuer, std::move(config));
+}
+
+base::Optional<int> TrustTokenStore::BatchSize(const url::Origin& issuer) {
+  DCHECK(!issuer.opaque());
+  std::unique_ptr<TrustTokenIssuerConfig> config =
+      persister_->GetIssuerConfig(issuer);
+  if (!config)
+    return base::nullopt;
+  if (!config->has_batch_size() || config->batch_size() <= 0)
+    return base::nullopt;
+  return config->batch_size();
+}
+
+void TrustTokenStore::AddTokens(const url::Origin& issuer,
+                                base::span<const std::string> token_bodies,
+                                base::StringPiece issuing_key) {
+  DCHECK(!issuer.opaque());
+  auto config = persister_->GetIssuerConfig(issuer);
+  DCHECK(config &&
+         std::any_of(config->keys().begin(), config->keys().end(),
+                     [issuing_key](const TrustTokenKeyCommitment& commitment) {
+                       return commitment.key() == issuing_key;
+                     }));
+
+  for (const auto& token_body : token_bodies) {
+    TrustToken* entry = config->add_tokens();
+    entry->set_body(token_body);
+    entry->set_signing_key(std::string(issuing_key));
+  }
+
+  persister_->SetIssuerConfig(issuer, std::move(config));
+}
+
+std::vector<TrustToken> TrustTokenStore::RetrieveMatchingTokens(
+    const url::Origin& issuer,
+    base::RepeatingCallback<bool(const std::string&)> key_matcher) {
+  DCHECK(!issuer.opaque());
+  auto config = persister_->GetIssuerConfig(issuer);
+  std::vector<TrustToken> matching_tokens;
+  if (!config)
+    return matching_tokens;
+
+  std::copy_if(config->tokens().begin(), config->tokens().end(),
+               std::back_inserter(matching_tokens),
+               [&key_matcher](const TrustToken& token) {
+                 return token.has_signing_key() &&
+                        key_matcher.Run(token.signing_key());
+               });
+
+  return matching_tokens;
+}
+
+void TrustTokenStore::DeleteToken(const url::Origin& issuer,
+                                  const TrustToken& to_delete) {
+  DCHECK(!issuer.opaque());
+  auto config = persister_->GetIssuerConfig(issuer);
+  if (!config)
+    return;
+
+  for (auto it = config->mutable_tokens()->begin();
+       it != config->mutable_tokens()->end(); ++it) {
+    if (it->body() == to_delete.body()) {
+      config->mutable_tokens()->erase(it);
+      break;
+    }
+  }
+
+  persister_->SetIssuerConfig(issuer, std::move(config));
+}
+
+void TrustTokenStore::SetRedemptionRecord(
+    const url::Origin& issuer,
+    const url::Origin& top_level,
+    const SignedTrustTokenRedemptionRecord& record) {
+  DCHECK(!issuer.opaque());
+  DCHECK(!top_level.opaque());
+  auto config = persister_->GetIssuerToplevelPairConfig(issuer, top_level);
+  if (!config)
+    config = std::make_unique<TrustTokenIssuerToplevelPairConfig>();
+  *config->mutable_signed_redemption_record() = record;
+  persister_->SetIssuerToplevelPairConfig(issuer, top_level, std::move(config));
+}
+
+base::Optional<SignedTrustTokenRedemptionRecord>
+TrustTokenStore::RetrieveNonstaleRedemptionRecord(
+    const url::Origin& issuer,
+    const url::Origin& top_level) {
+  DCHECK(!issuer.opaque());
+  DCHECK(!top_level.opaque());
+  auto config = persister_->GetIssuerToplevelPairConfig(issuer, top_level);
+  if (!config)
+    return base::nullopt;
+
+  if (!config->has_signed_redemption_record())
+    return base::nullopt;
+
+  if (record_expiry_delegate_->IsRecordExpired(
+          config->signed_redemption_record()))
+    return base::nullopt;
+
+  return config->signed_redemption_record();
+}
+
+}  // namespace net
diff --git a/net/trust_tokens/trust_token_store.h b/net/trust_tokens/trust_token_store.h
new file mode 100644
index 0000000..374db08
--- /dev/null
+++ b/net/trust_tokens/trust_token_store.h
@@ -0,0 +1,224 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_TRUST_TOKENS_TRUST_TOKEN_STORE_H_
+#define NET_TRUST_TOKENS_TRUST_TOKEN_STORE_H_
+
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "base/optional.h"
+#include "base/time/time.h"
+#include "net/trust_tokens/proto/public.pb.h"
+#include "net/trust_tokens/trust_token_persister.h"
+#include "net/trust_tokens/types.h"
+#include "url/origin.h"
+
+namespace net {
+
+// A TrustTokenStore provides operations on persistent state necessary for
+// the various steps of the Trust TrustTokens protocol.
+//
+// For more information about the protocol, see the explainer at
+// https://github.com/WICG/trust-token-api.
+//
+// TrustTokenStore translates operations germane to different steps
+// of token issuance, token redemption, and request signing into
+// operations in the key-value representation used by the persistence
+// layer.
+//
+// For example, it provides operations:
+// - checking preconditions for the different protocol steps;
+// - storing unblinded, signed tokens; and
+// - managing Signed Redemption Records (SRRs) and corresponding key pairs.
+//
+// TrustTokenStore's methods do minimal precondition checking and, in
+// particular, only selectively verify protocol-level invariants and
+// input integrity.
+class TrustTokenStore {
+ public:
+  class RecordExpiryDelegate {
+   public:
+    virtual ~RecordExpiryDelegate() = default;
+
+    // Returns whether the given Signed Redemption Record has expired.
+    // This is implemented with a delegate to abstract away reading
+    // the values of SRRs (they're opaque to this store).
+    virtual bool IsRecordExpired(
+        const SignedTrustTokenRedemptionRecord& record) = 0;
+  };
+
+  // Creates a new TrustTokenStore passing read and write operations through
+  // to the given persister.
+  //
+  // Until the underlying BoringSSL functionality is implemented to extract
+  // expiry timestamps from Signed Redemption Record bodies, defaults to
+  // never expiring stored SRRs.
+  //
+  // |persister| must not be null.
+  explicit TrustTokenStore(std::unique_ptr<TrustTokenPersister> persister);
+
+  // Creates a TrustTokenStore relying on the given delegate for judging whether
+  // signed redemption records have expired.
+  //
+  // |persister| must not be null.
+  TrustTokenStore(
+      std::unique_ptr<TrustTokenPersister> persister,
+      std::unique_ptr<RecordExpiryDelegate> expiry_delegate_for_testing);
+
+  virtual ~TrustTokenStore();
+
+  //// Methods related to ratelimits:
+
+  // Updates the given issuer's last issuance time to now.
+  //
+  // |issuer| must not be opaque.
+  virtual void RecordIssuance(const url::Origin& issuer);
+
+  // Returns the time since the last call to RecordIssuance for
+  // issuer |issuer|, or nullopt in the following two cases:
+  // 1. there is no currently-recorded prior issuance for the
+  // issuer, or
+  // 2. the time since the last issuance is negative (because
+  // of, for instance, corruption or clock skew).
+  //
+  // |issuer| must not be opaque.
+  WARN_UNUSED_RESULT virtual base::Optional<base::TimeDelta>
+  TimeSinceLastIssuance(const url::Origin& issuer);
+
+  // Updates the given (issuer, top-level) origin pair's last redemption time
+  // to now.
+  //
+  // |issuer| and |top_level| must not be opaque.
+  virtual void RecordRedemption(const url::Origin& issuer,
+                                const url::Origin& top_level);
+
+  // Returns the time elapsed since the last redemption recorded by
+  // RecordRedemption for issuer |issuer| and top level |top_level|,
+  // or nullopt in the following two cases:
+  // 1. there was no prior redemption for the (issuer,
+  // top-level origin) pair.
+  // 2. the time since the last redepmption is negative (because
+  // of, for instance, corruption or clock skew).
+  //
+  // |issuer| and |top_level| must not be opaque.
+  WARN_UNUSED_RESULT virtual base::Optional<base::TimeDelta>
+  TimeSinceLastRedemption(const url::Origin& issuer,
+                          const url::Origin& top_level);
+
+  // Returns whether |issuer| is associated with |top_level|.
+  //
+  // |issuer| and |top_level| must not be opaque.
+  WARN_UNUSED_RESULT virtual bool IsAssociated(const url::Origin& issuer,
+                                               const url::Origin& top_level);
+
+  // Associates |issuer| with |top_level|. (It's the caller's responsibility to
+  // enforce any cap on the number of top levels per issuer.)
+  //
+  // |issuer| and |top_level| must not be opaque.
+  virtual void SetAssociation(const url::Origin& issuer,
+                              const url::Origin& top_level);
+
+  //// Methods related to reading and writing issuer values configured via key
+  //// commitment queries, such as key commitments and batch sizes:
+
+  // Returns all stored key commitments (including related metadata:
+  // see the definition of TrustTokenKeyCommitment) for the given issuer.
+  //
+  // |issuer| must not be opaque.
+  WARN_UNUSED_RESULT virtual std::vector<TrustTokenKeyCommitment>
+  KeyCommitments(const url::Origin& issuer);
+
+  // Sets the key commitments for |issuer| to exactly the keys in |keys|.
+  // If there is a key in |keys| with the same key() as a key already stored:
+  // - maintains the "first seen at" time for the key
+  // - updates the expiry date to the new expiry date, even if it is sooner
+  // than the previous expiry date
+  //
+  // Also prunes all state corresponding to keys *not* in |keys|:
+  // - removes all stored signed tokens for |issuer| that were signed with
+  // keys not in |keys|
+  // - removes all key commitments for |issuer| with keys not in |keys|
+  //
+  // It is the client's responsibility to validate the
+  // reasonableness of the given keys' expiry times. (For instance, one might
+  // wish to avoid providing keys with expiry times in the past.)
+  //
+  // |issuer| must not be opaque, and the commitments in |keys| must have
+  // distinct keys.
+  virtual void SetKeyCommitmentsAndPruneStaleState(
+      const url::Origin& issuer,
+      base::span<const TrustTokenKeyCommitment> keys);
+
+  // Returns the "batch size" (number of blinded tokens to provide per issuance
+  // request) for the given issuer, if present and greater than 0. Otherwise,
+  // returns nullopt.
+  //
+  // |issuer| must not be opaque.
+  WARN_UNUSED_RESULT virtual base::Optional<int> BatchSize(
+      const url::Origin& issuer);
+
+  // Sets the given issuer's batch size (see above).
+  //
+  // |issuer| must not be opaque; |batch_size| must be at least 1.
+  virtual void SetBatchSize(const url::Origin& issuer, int batch_size);
+
+  //// Methods related to reading and writing signed tokens:
+
+  // Associates to the given issuer additional signed
+  // trust tokens with:
+  // - token bodies given by |token_bodies|
+  // - signing keys given by |issuing_key|.
+  //
+  // |issuer| must not be opaque and must have a stored
+  // key commitment corresponding to |issuing_key|.
+  virtual void AddTokens(const url::Origin& issuer,
+                         base::span<const std::string> token_bodies,
+                         base::StringPiece issuing_key);
+
+  // Returns all signed tokens from |issuer| signed by keys matching
+  // the given predicate.
+  //
+  // |issuer| must not be opaque.
+  WARN_UNUSED_RESULT virtual std::vector<TrustToken> RetrieveMatchingTokens(
+      const url::Origin& issuer,
+      base::RepeatingCallback<bool(const std::string&)> key_matcher);
+
+  // If |to_delete| is a token issued by |issuer|, deletes the token.
+  //
+  // |issuer| must not be opaque.
+  void DeleteToken(const url::Origin& issuer, const TrustToken& to_delete);
+
+  //// Methods concerning Signed Redemption Records (SRRs)
+
+  // Sets the cached SRR corresponding to the pair (issuer, top_level)
+  // to |record|. Overwrites any existing record.
+  //
+  // |issuer| and |top_level| must not be opaque.
+  virtual void SetRedemptionRecord(
+      const url::Origin& issuer,
+      const url::Origin& top_level,
+      const SignedTrustTokenRedemptionRecord& record);
+
+  // Attempts to retrieve the stored SRR for the given pair of (issuer,
+  // top-level) origins.
+  // - If the pair has a current (i.e., non-expired) SRR, returns that SRR.
+  // - Otherwise, returns nullopt.
+  //
+  // |issuer| and |top_level| must not be opaque.
+  WARN_UNUSED_RESULT virtual base::Optional<SignedTrustTokenRedemptionRecord>
+  RetrieveNonstaleRedemptionRecord(const url::Origin& issuer,
+                                   const url::Origin& top_level);
+
+ private:
+  std::unique_ptr<TrustTokenPersister> persister_;
+  std::unique_ptr<RecordExpiryDelegate> record_expiry_delegate_;
+};
+
+}  // namespace net
+
+#endif  // NET_TRUST_TOKENS_TRUST_TOKEN_STORE_H_
diff --git a/net/trust_tokens/trust_token_store_unittest.cc b/net/trust_tokens/trust_token_store_unittest.cc
new file mode 100644
index 0000000..4f24782
--- /dev/null
+++ b/net/trust_tokens/trust_token_store_unittest.cc
@@ -0,0 +1,540 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/trust_tokens/trust_token_store.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/test/task_environment.h"
+#include "base/time/time.h"
+#include "net/trust_tokens/in_memory_trust_token_persister.h"
+#include "net/trust_tokens/proto/public.pb.h"
+#include "net/trust_tokens/proto/storage.pb.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "url/gurl.h"
+#include "url/origin.h"
+
+using ::testing::ElementsAre;
+using ::testing::Optional;
+
+namespace net {
+namespace trust_tokens {
+
+namespace {
+MATCHER_P(EqualsProto,
+          message,
+          "Match a proto Message equal to the matcher's argument.") {
+  std::string expected_serialized, actual_serialized;
+  message.SerializeToString(&expected_serialized);
+  arg.SerializeToString(&actual_serialized);
+  return expected_serialized == actual_serialized;
+}
+}  // namespace
+
+TEST(TrustTokenStoreTest, RecordsIssuances) {
+  // A newly initialized store should not think it's
+  // recorded any issuances.
+
+  TrustTokenStore my_store(std::make_unique<InMemoryTrustTokenPersister>());
+  url::Origin issuer = url::Origin::Create(GURL("https://issuer.com"));
+  base::test::TaskEnvironment env(
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
+
+  EXPECT_EQ(my_store.TimeSinceLastIssuance(issuer), base::nullopt);
+
+  // Recording an issuance should result in the time
+  // since last issuance being correctly returned.
+
+  my_store.RecordIssuance(issuer);
+  auto delta = base::TimeDelta::FromSeconds(1);
+  env.AdvanceClock(delta);
+
+  EXPECT_THAT(my_store.TimeSinceLastIssuance(issuer), Optional(delta));
+}
+
+TEST(TrustTokenStoreTest, DoesntReportMissingOrMalformedIssuanceTimestamps) {
+  auto my_persister = std::make_unique<InMemoryTrustTokenPersister>();
+  auto* raw_persister = my_persister.get();
+
+  TrustTokenStore my_store(std::move(my_persister));
+  url::Origin issuer = url::Origin::Create(GURL("https://issuer.com"));
+
+  auto issuer_config_with_no_time = std::make_unique<TrustTokenIssuerConfig>();
+  raw_persister->SetIssuerConfig(issuer, std::move(issuer_config_with_no_time));
+
+  EXPECT_EQ(my_store.TimeSinceLastIssuance(issuer), base::nullopt);
+
+  auto issuer_config_with_malformed_time =
+      std::make_unique<TrustTokenIssuerConfig>();
+  issuer_config_with_malformed_time->set_last_issuance(
+      "not a valid serialization of a base::Time");
+  raw_persister->SetIssuerConfig(issuer,
+                                 std::move(issuer_config_with_malformed_time));
+
+  EXPECT_EQ(my_store.TimeSinceLastIssuance(issuer), base::nullopt);
+}
+
+TEST(TrustTokenStoreTest, DoesntReportNegativeTimeSinceLastIssuance) {
+  auto my_persister = std::make_unique<InMemoryTrustTokenPersister>();
+  auto* raw_persister = my_persister.get();
+  base::test::TaskEnvironment env(
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
+
+  TrustTokenStore my_store(std::move(my_persister));
+  url::Origin issuer = url::Origin::Create(GURL("https://issuer.com"));
+  base::Time later_than_now =
+      base::Time::Now() + base::TimeDelta::FromSeconds(1);
+
+  auto issuer_config_with_future_time =
+      std::make_unique<TrustTokenIssuerConfig>();
+  issuer_config_with_future_time->set_last_issuance(
+      internal::TimeToString(later_than_now));
+  raw_persister->SetIssuerConfig(issuer,
+                                 std::move(issuer_config_with_future_time));
+
+  // TimeSinceLastIssuance shouldn't return negative values.
+
+  EXPECT_EQ(my_store.TimeSinceLastIssuance(issuer), base::nullopt);
+}
+
+TEST(TrustTokenStore, RecordsRedemptions) {
+  // A newly initialized store should not think it's
+  // recorded any redemptions.
+
+  TrustTokenStore my_store(std::make_unique<InMemoryTrustTokenPersister>());
+  url::Origin issuer = url::Origin::Create(GURL("https://issuer.com"));
+  url::Origin toplevel = url::Origin::Create(GURL("https://toplevel.com"));
+  base::test::TaskEnvironment env(
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
+
+  EXPECT_EQ(my_store.TimeSinceLastRedemption(issuer, toplevel), base::nullopt);
+
+  // Recording a redemption should result in the time
+  // since last redemption being correctly returned.
+
+  my_store.RecordRedemption(issuer, toplevel);
+  auto delta = base::TimeDelta::FromSeconds(1);
+  env.AdvanceClock(delta);
+
+  EXPECT_THAT(my_store.TimeSinceLastRedemption(issuer, toplevel),
+              Optional(delta));
+}
+
+TEST(TrustTokenStoreTest, DoesntReportMissingOrMalformedRedemptionTimestamps) {
+  auto my_persister = std::make_unique<InMemoryTrustTokenPersister>();
+  auto* raw_persister = my_persister.get();
+
+  TrustTokenStore my_store(std::move(my_persister));
+  url::Origin issuer = url::Origin::Create(GURL("https://issuer.com"));
+  url::Origin toplevel = url::Origin::Create(GURL("https://toplevel.com"));
+
+  auto config_with_no_time =
+      std::make_unique<TrustTokenIssuerToplevelPairConfig>();
+  raw_persister->SetIssuerToplevelPairConfig(issuer, toplevel,
+                                             std::move(config_with_no_time));
+
+  EXPECT_EQ(my_store.TimeSinceLastRedemption(issuer, toplevel), base::nullopt);
+
+  auto config_with_malformed_time =
+      std::make_unique<TrustTokenIssuerToplevelPairConfig>();
+  config_with_malformed_time->set_last_redemption(
+      "not a valid serialization of a base::Time");
+  raw_persister->SetIssuerToplevelPairConfig(
+      issuer, toplevel, std::move(config_with_malformed_time));
+
+  EXPECT_EQ(my_store.TimeSinceLastRedemption(issuer, toplevel), base::nullopt);
+}
+
+TEST(TrustTokenStoreTest, DoesntReportNegativeTimeSinceLastRedemption) {
+  auto my_persister = std::make_unique<InMemoryTrustTokenPersister>();
+  auto* raw_persister = my_persister.get();
+  TrustTokenStore my_store(std::move(my_persister));
+  base::test::TaskEnvironment env(
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
+
+  url::Origin issuer = url::Origin::Create(GURL("https://issuer.com"));
+  url::Origin toplevel = url::Origin::Create(GURL("https://toplevel.com"));
+
+  base::Time later_than_now =
+      base::Time::Now() + base::TimeDelta::FromSeconds(1);
+
+  auto config_with_future_time =
+      std::make_unique<TrustTokenIssuerToplevelPairConfig>();
+  config_with_future_time->set_last_redemption(
+      internal::TimeToString(later_than_now));
+
+  raw_persister->SetIssuerToplevelPairConfig(
+      issuer, toplevel, std::move(config_with_future_time));
+
+  // TimeSinceLastRedemption shouldn't return negative values.
+
+  EXPECT_EQ(my_store.TimeSinceLastRedemption(issuer, toplevel), base::nullopt);
+}
+
+TEST(TrustTokenStore, AssociatesToplevelsWithIssuers) {
+  // A newly initialized store should not think
+  // any toplevels are associated with any issuers.
+
+  TrustTokenStore my_store(std::make_unique<InMemoryTrustTokenPersister>());
+  url::Origin issuer = url::Origin::Create(GURL("https://issuer.com"));
+  url::Origin toplevel = url::Origin::Create(GURL("https://toplevel.com"));
+  EXPECT_FALSE(my_store.IsAssociated(issuer, toplevel));
+
+  // After associating an issuer with a toplevel,
+  // the store should think that that issuer is associated
+  // with that toplevel.
+
+  my_store.SetAssociation(issuer, toplevel);
+  EXPECT_TRUE(my_store.IsAssociated(issuer, toplevel));
+}
+
+TEST(TrustTokenStore, StoresKeyCommitments) {
+  // A newly initialized store should not think
+  // any issuers have committed keys.
+
+  TrustTokenStore my_store(std::make_unique<InMemoryTrustTokenPersister>());
+  url::Origin issuer = url::Origin::Create(GURL("https://issuer.com"));
+  EXPECT_TRUE(my_store.KeyCommitments(issuer).empty());
+
+  // A stored committed key should be returned
+  // by a subsequent query.
+
+  TrustTokenKeyCommitment my_commitment;
+  my_commitment.set_key("quite a secure key, this");
+  my_store.SetKeyCommitmentsAndPruneStaleState(
+      issuer, std::vector<TrustTokenKeyCommitment>{my_commitment});
+
+  EXPECT_THAT(my_store.KeyCommitments(issuer),
+              ElementsAre(EqualsProto(my_commitment)));
+}
+
+TEST(TrustTokenStore, OverwritesExistingKeyCommitments) {
+  // Overwriting an existing committed key should lead
+  // to the key's metadata being fused:
+  // - the key should still be present
+  // - the "first seen at" should not change
+  // - the expiry date should be updated
+
+  TrustTokenStore my_store(std::make_unique<InMemoryTrustTokenPersister>());
+  url::Origin issuer = url::Origin::Create(GURL("https://issuer.com"));
+
+  const std::string kMyKey = "quite a secure key, this";
+  TrustTokenKeyCommitment my_commitment;
+  my_commitment.set_key(kMyKey);
+
+  const std::string kMySerializedTime = "four o'clock";
+  const std::string kReplacementSerializedTime = "five o'clock";
+  my_commitment.set_expiry(kMySerializedTime);
+  my_commitment.set_first_seen_at(kMySerializedTime);
+
+  my_store.SetKeyCommitmentsAndPruneStaleState(
+      issuer, std::vector<TrustTokenKeyCommitment>{my_commitment});
+
+  TrustTokenKeyCommitment replacement_commitment;
+  replacement_commitment.set_key(kMyKey);
+  replacement_commitment.set_expiry(kReplacementSerializedTime);
+  replacement_commitment.set_first_seen_at(kReplacementSerializedTime);
+
+  my_store.SetKeyCommitmentsAndPruneStaleState(
+      issuer, std::vector<TrustTokenKeyCommitment>{replacement_commitment});
+
+  ASSERT_EQ(my_store.KeyCommitments(issuer).size(), 1u);
+  auto got = my_store.KeyCommitments(issuer).front();
+
+  EXPECT_TRUE(got.key() == kMyKey);
+  EXPECT_TRUE(got.first_seen_at() == kMySerializedTime);
+  EXPECT_TRUE(got.expiry() == kReplacementSerializedTime);
+}
+
+TEST(TrustTokenStore, KeyUpdateRemovesNonupdatedKeys) {
+  TrustTokenStore my_store(std::make_unique<InMemoryTrustTokenPersister>());
+  url::Origin issuer = url::Origin::Create(GURL("https://issuer.com"));
+
+  TrustTokenKeyCommitment my_commitment;
+  my_commitment.set_key("quite a secure key, this");
+  my_store.SetKeyCommitmentsAndPruneStaleState(
+      issuer, std::vector<TrustTokenKeyCommitment>{my_commitment});
+
+  // When committed keys are changed, the store should
+  // remove all keys not present in the provided set.
+  my_store.SetKeyCommitmentsAndPruneStaleState(
+      issuer, std::vector<TrustTokenKeyCommitment>());
+
+  EXPECT_TRUE(my_store.KeyCommitments(issuer).empty());
+}
+
+TEST(TrustTokenStore, PrunesDataAssociatedWithRemovedKeyCommitments) {
+  // Removing a committed key should result in trust tokens
+  // associated with the removed key being pruned from the store.
+  TrustTokenStore my_store(std::make_unique<InMemoryTrustTokenPersister>());
+  url::Origin issuer = url::Origin::Create(GURL("https://issuer.com"));
+
+  TrustTokenKeyCommitment my_commitment;
+  my_commitment.set_key("quite a secure key, this");
+
+  TrustTokenKeyCommitment another_commitment;
+  another_commitment.set_key("distinct from the first key");
+
+  my_store.SetKeyCommitmentsAndPruneStaleState(
+      issuer,
+      std::vector<TrustTokenKeyCommitment>{my_commitment, another_commitment});
+
+  my_store.AddTokens(issuer, std::vector<std::string>{"some token body"},
+                     my_commitment.key());
+
+  my_store.AddTokens(issuer, std::vector<std::string>{"some other token body"},
+                     another_commitment.key());
+
+  my_store.SetKeyCommitmentsAndPruneStaleState(
+      issuer, std::vector<TrustTokenKeyCommitment>{another_commitment});
+
+  TrustToken expected_token;
+  expected_token.set_body("some other token body");
+  expected_token.set_signing_key(another_commitment.key());
+
+  // Removing |my_commitment| should have
+  // - led to the removal of the token associated with the removed key and
+  // - *not* led to the removal of the token associated with the remaining key.
+  EXPECT_THAT(my_store.RetrieveMatchingTokens(
+                  issuer, base::BindRepeating(
+                              [](const std::string& t) { return true; })),
+              ElementsAre(EqualsProto(expected_token)));
+}
+
+TEST(TrustTokenStore, SetsBatchSize) {
+  // A newly initialized store should not think
+  // any issuers have associated batch sizes.
+  auto my_persister = std::make_unique<InMemoryTrustTokenPersister>();
+  auto* raw_persister = my_persister.get();
+  TrustTokenStore my_store(std::move(my_persister));
+  url::Origin issuer = url::Origin::Create(GURL("https://issuer.com"));
+
+  EXPECT_EQ(my_store.BatchSize(issuer), base::nullopt);
+
+  // Setting an issuer's batch size should mean that
+  // subsequent queries return that batch size.
+
+  my_store.SetBatchSize(issuer, 1);
+  EXPECT_THAT(my_store.BatchSize(issuer), Optional(1));
+
+  // If the issuer config is storing a bad batch size for some reason,
+  // the store's client should see nullopt.
+  auto bad_config = std::make_unique<TrustTokenIssuerConfig>();
+  bad_config->set_batch_size(-1);
+  raw_persister->SetIssuerConfig(issuer, std::move(bad_config));
+  EXPECT_EQ(my_store.BatchSize(issuer), base::nullopt);
+}
+
+TEST(TrustTokenStore, AddsTrustTokens) {
+  // A newly initialized store should not think
+  // any issuers have associated trust tokens.
+
+  TrustTokenStore my_store(std::make_unique<InMemoryTrustTokenPersister>());
+  url::Origin issuer = url::Origin::Create(GURL("https://issuer.com"));
+
+  auto match_all_keys =
+      base::BindRepeating([](const std::string& t) { return true; });
+
+  EXPECT_TRUE(my_store.RetrieveMatchingTokens(issuer, match_all_keys).empty());
+
+  // Adding a token should result in that token being
+  // returned by subsequent queries with predicates accepting
+  // that token.
+
+  const std::string kMyKey = "abcdef";
+  TrustTokenKeyCommitment my_commitment;
+  my_commitment.set_key(kMyKey);
+  my_store.SetKeyCommitmentsAndPruneStaleState(
+      issuer, std::vector<TrustTokenKeyCommitment>{my_commitment});
+
+  TrustToken expected_token;
+  expected_token.set_body("some token");
+  expected_token.set_signing_key(kMyKey);
+  my_store.AddTokens(issuer, std::vector<std::string>{expected_token.body()},
+                     kMyKey);
+
+  EXPECT_THAT(my_store.RetrieveMatchingTokens(issuer, match_all_keys),
+              ElementsAre(EqualsProto(expected_token)));
+}
+
+TEST(TrustTokenStore, RetrievesTrustTokensRespectingNontrivialPredicate) {
+  // RetrieveMatchingTokens should not return tokens rejected by
+  // the provided predicate.
+
+  TrustTokenStore my_store(std::make_unique<InMemoryTrustTokenPersister>());
+  url::Origin issuer = url::Origin::Create(GURL("https://issuer.com"));
+
+  const std::string kMatchingKey = "bbbbbb";
+  const std::string kNonmatchingKey = "aaaaaa";
+  TrustTokenKeyCommitment matching_commitment;
+  matching_commitment.set_key(kMatchingKey);
+
+  TrustTokenKeyCommitment nonmatching_commitment;
+  nonmatching_commitment.set_key(kNonmatchingKey);
+
+  TrustToken expected_token;
+  expected_token.set_body("this one should get returned");
+  expected_token.set_signing_key(kMatchingKey);
+
+  my_store.SetKeyCommitmentsAndPruneStaleState(
+      issuer, std::vector<TrustTokenKeyCommitment>{matching_commitment,
+                                                   nonmatching_commitment});
+
+  my_store.AddTokens(issuer, std::vector<std::string>{expected_token.body()},
+                     kMatchingKey);
+  my_store.AddTokens(
+      issuer,
+      std::vector<std::string>{"this one should get rejected by the predicate"},
+      kNonmatchingKey);
+
+  EXPECT_THAT(my_store.RetrieveMatchingTokens(
+                  issuer, base::BindRepeating(
+                              [](const std::string& pattern,
+                                 const std::string& possible_match) {
+                                return possible_match == pattern;
+                              },
+                              kMatchingKey)),
+              ElementsAre(EqualsProto(expected_token)));
+}
+
+TEST(TrustTokenStore, DeletesSingleToken) {
+  TrustTokenStore my_store(std::make_unique<InMemoryTrustTokenPersister>());
+  url::Origin issuer = url::Origin::Create(GURL("https://issuer.com"));
+  auto match_all_keys =
+      base::BindRepeating([](const std::string& t) { return true; });
+
+  // Deleting a single token should result in that token
+  // not being returned by subsequent RetrieveMatchingTokens calls.
+  // On the other hand, tokens *not* deleted should still be
+  // returned.
+
+  TrustTokenKeyCommitment my_commitment;
+  my_commitment.set_key("key");
+
+  TrustToken first_token;
+  first_token.set_body("delete me!");
+  first_token.set_signing_key(my_commitment.key());
+
+  TrustToken second_token;
+  second_token.set_body("don't delete me!");
+  second_token.set_signing_key(my_commitment.key());
+
+  my_store.SetKeyCommitmentsAndPruneStaleState(
+      issuer, std::vector<TrustTokenKeyCommitment>{my_commitment});
+  my_store.AddTokens(
+      issuer, std::vector<std::string>{first_token.body(), second_token.body()},
+      my_commitment.key());
+
+  my_store.DeleteToken(issuer, first_token);
+
+  EXPECT_THAT(my_store.RetrieveMatchingTokens(issuer, match_all_keys),
+              ElementsAre(EqualsProto(second_token)));
+}
+
+TEST(TrustTokenStore, DeleteTokenForMissingIssuer) {
+  TrustTokenStore my_store(std::make_unique<InMemoryTrustTokenPersister>());
+  url::Origin issuer = url::Origin::Create(GURL("https://issuer.com"));
+
+  // Deletes for issuers not present in the store should gracefully no-op.
+
+  my_store.DeleteToken(issuer, TrustToken());
+}
+
+TEST(TrustTokenStore, SetsAndRetrievesRedemptionRecord) {
+  // A newly initialized store should not think
+  // it has any signed redemption records.
+
+  TrustTokenStore my_store(std::make_unique<InMemoryTrustTokenPersister>());
+  url::Origin issuer = url::Origin::Create(GURL("https://issuer.com"));
+  url::Origin toplevel = url::Origin::Create(GURL("https://toplevel.com"));
+  base::test::TaskEnvironment env(
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
+
+  EXPECT_EQ(my_store.RetrieveNonstaleRedemptionRecord(issuer, toplevel),
+            base::nullopt);
+
+  // Providing a redemption record should mean that subsequent
+  // queries (modulo the record's staleness) should return that
+  // record.
+
+  SignedTrustTokenRedemptionRecord my_record;
+  my_record.set_body("Look at me! I'm a signed redemption record!");
+  my_store.SetRedemptionRecord(issuer, toplevel, my_record);
+
+  EXPECT_THAT(my_store.RetrieveNonstaleRedemptionRecord(issuer, toplevel),
+              Optional(EqualsProto(my_record)));
+}
+
+TEST(TrustTokenStore, RetrieveRedemptionRecordHandlesConfigWithNoRecord) {
+  // A RetrieveRedemptionRecord call for an (issuer, toplevel) pair with
+  // no redemption record stored should gracefully return the default value.
+
+  auto my_persister = std::make_unique<InMemoryTrustTokenPersister>();
+  auto* raw_persister = my_persister.get();
+  TrustTokenStore my_store(std::move(my_persister));
+  url::Origin issuer = url::Origin::Create(GURL("https://issuer.com"));
+  url::Origin toplevel = url::Origin::Create(GURL("https://toplevel.com"));
+
+  raw_persister->SetIssuerToplevelPairConfig(
+      issuer, toplevel, std::make_unique<TrustTokenIssuerToplevelPairConfig>());
+
+  EXPECT_EQ(my_store.RetrieveNonstaleRedemptionRecord(issuer, toplevel),
+            base::nullopt);
+}
+
+TEST(TrustTokenStore, SetRedemptionRecordOverwritesExisting) {
+  // Subsequent redemption records should overwrite ones set earlier.
+
+  TrustTokenStore my_store(std::make_unique<InMemoryTrustTokenPersister>());
+  url::Origin issuer = url::Origin::Create(GURL("https://issuer.com"));
+  url::Origin toplevel = url::Origin::Create(GURL("https://toplevel.com"));
+  base::test::TaskEnvironment env(
+      base::test::TaskEnvironment::TimeSource::MOCK_TIME);
+
+  SignedTrustTokenRedemptionRecord my_record;
+  my_record.set_body("Look at me! I'm a signed redemption record!");
+  my_store.SetRedemptionRecord(issuer, toplevel, my_record);
+
+  SignedTrustTokenRedemptionRecord another_record;
+  another_record.set_body(
+      "If all goes well, this one should overwrite |my_record|.");
+  my_store.SetRedemptionRecord(issuer, toplevel, another_record);
+
+  EXPECT_THAT(my_store.RetrieveNonstaleRedemptionRecord(issuer, toplevel),
+              Optional(EqualsProto(another_record)));
+}
+
+namespace {
+// Characterizes an SRR as expired if its body begins with an "a".
+class LetterAExpiringExpiryDelegate
+    : public TrustTokenStore::RecordExpiryDelegate {
+ public:
+  bool IsRecordExpired(
+      const SignedTrustTokenRedemptionRecord& record) override {
+    return record.body().size() > 1 && record.body().front() == 'a';
+  }
+};
+}  // namespace
+
+TEST(TrustTokenStore, DoesNotReturnStaleRedemptionRecord) {
+  // Once a redemption record expires, it should no longer
+  // be returned by retrieval queries.
+  TrustTokenStore my_store(std::make_unique<InMemoryTrustTokenPersister>(),
+                           std::make_unique<LetterAExpiringExpiryDelegate>());
+  url::Origin issuer = url::Origin::Create(GURL("https://issuer.com"));
+  url::Origin toplevel = url::Origin::Create(GURL("https://toplevel.com"));
+
+  SignedTrustTokenRedemptionRecord my_record;
+  my_record.set_body("aLook at me! I'm an expired signed redemption record!");
+  my_store.SetRedemptionRecord(issuer, toplevel, my_record);
+
+  EXPECT_EQ(my_store.RetrieveNonstaleRedemptionRecord(issuer, toplevel),
+            base::nullopt);
+}
+
+}  // namespace trust_tokens
+}  // namespace net
diff --git a/net/trust_tokens/types.cc b/net/trust_tokens/types.cc
new file mode 100644
index 0000000..829d027c
--- /dev/null
+++ b/net/trust_tokens/types.cc
@@ -0,0 +1,26 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/trust_tokens/types.h"
+#include "base/time/time.h"
+#include "base/value_conversions.h"
+#include "base/values.h"
+#include "url/origin.h"
+
+namespace net {
+namespace internal {
+
+base::Optional<base::Time> StringToTime(base::StringPiece my_string) {
+  base::Time ret;
+  if (!base::GetValueAsTime(base::Value(my_string), &ret))
+    return base::nullopt;
+  return ret;
+}
+
+std::string TimeToString(base::Time my_time) {
+  return base::CreateTimeValue(my_time).GetString();
+}
+
+}  // namespace internal
+}  // namespace net
diff --git a/net/trust_tokens/types.h b/net/trust_tokens/types.h
new file mode 100644
index 0000000..47338017
--- /dev/null
+++ b/net/trust_tokens/types.h
@@ -0,0 +1,30 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_TRUST_TOKENS_TYPES_H_
+#define NET_TRUST_TOKENS_TYPES_H_
+
+#include <string>
+
+#include "base/strings/string_piece_forward.h"
+#include "base/time/time.h"
+#include "url/origin.h"
+
+namespace net {
+namespace internal {
+
+// types.h provides utility functions for Trust TrustTokens type conversion.
+
+// Deserializes a base::Time. Returns nullopt on failure (for instance,
+// deserialization can fail if |my_string| is malformed due to data
+// corruption) and the deserialized Time on success.
+base::Optional<base::Time> StringToTime(base::StringPiece my_string);
+
+// Serializes a base::Time.
+std::string TimeToString(base::Time my_time);
+
+}  // namespace internal
+}  // namespace net
+
+#endif  // NET_TRUST_TOKENS_TYPES_H_
diff --git a/net/trust_tokens/types_unittest.cc b/net/trust_tokens/types_unittest.cc
new file mode 100644
index 0000000..7830f87
--- /dev/null
+++ b/net/trust_tokens/types_unittest.cc
@@ -0,0 +1,32 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/trust_tokens/types.h"
+#include "base/time/time.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::Optional;
+
+namespace net {
+namespace internal {
+
+// trust_tokens/types.h's TimeToString/StringToTime implementations are
+// thin wrappers around well-tested //base conversion methods, so these
+// tests are just sanity checks to make sure that values are actually
+// getting passed to the pertinent //base libraries.
+
+TEST(TrustTokenTypes, TimeToStringRoundtrip) {
+  auto my_time = base::Time::UnixEpoch() + base::TimeDelta::FromMilliseconds(
+                                               373849174829374);  // arbitrary
+  EXPECT_THAT(StringToTime(TimeToString(my_time)), Optional(my_time));
+}
+
+TEST(TrustTokenTypes, TimeFromBadStringFails) {
+  EXPECT_EQ(StringToTime("I bet this isn't a valid representation of a time."),
+            base::nullopt);
+}
+
+}  // namespace internal
+}  // namespace net
diff --git a/net/url_request/http_with_dns_over_https_unittest.cc b/net/url_request/http_with_dns_over_https_unittest.cc
index 12fe95c0..d4f1d9e 100644
--- a/net/url_request/http_with_dns_over_https_unittest.cc
+++ b/net/url_request/http_with_dns_over_https_unittest.cc
@@ -313,7 +313,7 @@
   EXPECT_EQ(test_https_requests_served_, 0u);
 
   EXPECT_TRUE(d.response_completed());
-  EXPECT_EQ(d.request_status(), net::ERR_DNS_MALFORMED_RESPONSE);
+  EXPECT_EQ(d.request_status(), net::ERR_NAME_NOT_RESOLVED);
 
   const auto& resolve_error_info = req->response_info().resolve_error_info;
   EXPECT_TRUE(resolve_error_info.is_secure_network_error);
diff --git a/remoting/protocol/webrtc_transport.cc b/remoting/protocol/webrtc_transport.cc
index 8645851..8e91675 100644
--- a/remoting/protocol/webrtc_transport.cc
+++ b/remoting/protocol/webrtc_transport.cc
@@ -288,8 +288,10 @@
 
     rtc_config.sdp_semantics = webrtc::SdpSemantics::kUnifiedPlan;
 
+    webrtc::PeerConnectionDependencies dependencies(this);
+    dependencies.allocator = std::move(port_allocator);
     peer_connection_ = peer_connection_factory_->CreatePeerConnection(
-        rtc_config, std::move(port_allocator), nullptr, this);
+        rtc_config, std::move(dependencies));
   }
 
   ~PeerConnectionWrapper() override {
diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc
index 3d8b23d8..a23f8eb 100644
--- a/services/network/cors/cors_url_loader.cc
+++ b/services/network/cors/cors_url_loader.cc
@@ -91,6 +91,7 @@
     uint32_t options,
     DeleteCallback delete_callback,
     const ResourceRequest& resource_request,
+    bool ignore_isolated_world_origin,
     mojo::PendingRemote<mojom::URLLoaderClient> client,
     const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
     mojom::URLLoaderFactory* network_loader_factory,
@@ -109,6 +110,9 @@
       origin_access_list_(origin_access_list),
       factory_bound_origin_access_list_(factory_bound_origin_access_list),
       preflight_controller_(preflight_controller) {
+  if (ignore_isolated_world_origin)
+    request_.isolated_world_origin = base::nullopt;
+
   receiver_.set_disconnect_handler(
       base::BindOnce(&CorsURLLoader::OnMojoDisconnect, base::Unretained(this)));
   DCHECK(network_loader_factory_);
diff --git a/services/network/cors/cors_url_loader.h b/services/network/cors/cors_url_loader.h
index 159d304..a3e3b72 100644
--- a/services/network/cors/cors_url_loader.h
+++ b/services/network/cors/cors_url_loader.h
@@ -44,6 +44,7 @@
       uint32_t options,
       DeleteCallback delete_callback,
       const ResourceRequest& resource_request,
+      bool ignore_isolated_world_origin,
       mojo::PendingRemote<mojom::URLLoaderClient> client,
       const net::MutableNetworkTrafficAnnotationTag& traffic_annotation,
       mojom::URLLoaderFactory* network_loader_factory,
diff --git a/services/network/cors/cors_url_loader_factory.cc b/services/network/cors/cors_url_loader_factory.cc
index e91b2db..af1c74c 100644
--- a/services/network/cors/cors_url_loader_factory.cc
+++ b/services/network/cors/cors_url_loader_factory.cc
@@ -125,6 +125,7 @@
       disable_web_security_(params->disable_web_security),
       process_id_(params->process_id),
       request_initiator_site_lock_(params->request_initiator_site_lock),
+      ignore_isolated_world_origin_(params->ignore_isolated_world_origin),
       origin_access_list_(origin_access_list) {
   DCHECK(context_);
   DCHECK(origin_access_list_);
@@ -200,8 +201,8 @@
         std::move(receiver), routing_id, request_id, options,
         base::BindOnce(&CorsURLLoaderFactory::DestroyURLLoader,
                        base::Unretained(this)),
-        resource_request, std::move(client), traffic_annotation,
-        inner_url_loader_factory, origin_access_list_,
+        resource_request, ignore_isolated_world_origin_, std::move(client),
+        traffic_annotation, inner_url_loader_factory, origin_access_list_,
         factory_bound_origin_access_list_.get(),
         context_->cors_preflight_controller());
     auto* raw_loader = loader.get();
diff --git a/services/network/cors/cors_url_loader_factory.h b/services/network/cors/cors_url_loader_factory.h
index ebf9480..9c81a2c 100644
--- a/services/network/cors/cors_url_loader_factory.h
+++ b/services/network/cors/cors_url_loader_factory.h
@@ -93,6 +93,7 @@
   const bool disable_web_security_;
   const int32_t process_id_ = mojom::kInvalidProcessId;
   const base::Optional<url::Origin> request_initiator_site_lock_;
+  const bool ignore_isolated_world_origin_;
 
   // Relative order of |network_loader_factory_| and |loaders_| matters -
   // URLLoaderFactory needs to live longer than URLLoaders created using the
diff --git a/services/network/cors/cors_url_loader_unittest.cc b/services/network/cors/cors_url_loader_unittest.cc
index af70995f..1f05fd8d 100644
--- a/services/network/cors/cors_url_loader_unittest.cc
+++ b/services/network/cors/cors_url_loader_unittest.cc
@@ -327,7 +327,8 @@
 
   void ResetFactory(base::Optional<url::Origin> initiator,
                     uint32_t process_id,
-                    bool is_trusted = false) {
+                    bool is_trusted,
+                    bool ignore_isolated_world_origin) {
     test_url_loader_factory_ = std::make_unique<TestURLLoaderFactory>();
     test_url_loader_factory_receiver_ =
         std::make_unique<mojo::Receiver<mojom::URLLoaderFactory>>(
@@ -347,6 +348,7 @@
     factory_params->is_trusted = is_trusted;
     factory_params->process_id = process_id;
     factory_params->is_corb_enabled = (process_id != mojom::kBrowserProcessId);
+    factory_params->ignore_isolated_world_origin = ignore_isolated_world_origin;
     factory_params->factory_override = mojom::URLLoaderFactoryOverride::New();
     factory_params->factory_override->overriding_factory =
         test_url_loader_factory_receiver_->BindNewPipeAndPassRemote();
@@ -362,6 +364,13 @@
         &origin_access_list_);
   }
 
+  void ResetFactory(base::Optional<url::Origin> initiator,
+                    uint32_t process_id) {
+    auto params = network::mojom::URLLoaderFactoryParams::New();
+    ResetFactory(initiator, process_id, params->is_trusted,
+                 params->ignore_isolated_world_origin);
+  }
+
   NetworkContext* network_context() { return network_context_.get(); }
 
  private:
@@ -1264,12 +1273,16 @@
 // Tests if CorsURLLoader takes into account
 // ResourceRequest::isolated_world_origin when consulting OriginAccessList.
 TEST_F(CorsURLLoaderTest, OriginAccessList_IsolatedWorldOrigin) {
-  const GURL main_world_origin("http://main-world.com");
-  const GURL isolated_world_origin("http://isolated-world.com");
+  const url::Origin main_world_origin =
+      url::Origin::Create(GURL("http://main-world.com"));
+  const url::Origin isolated_world_origin =
+      url::Origin::Create(GURL("http://isolated-world.com"));
   const GURL url("http://other.com/foo.png");
 
-  AddAllowListEntryForOrigin(url::Origin::Create(isolated_world_origin),
-                             url.scheme(), url.host(),
+  ResetFactory(main_world_origin, kRendererProcessId, false /* trusted */,
+               false /* ignore_isolated_world_origin */);
+
+  AddAllowListEntryForOrigin(isolated_world_origin, url.scheme(), url.host(),
                              mojom::CorsDomainMatchMode::kDisallowSubdomains);
 
   ResourceRequest request;
@@ -1277,8 +1290,8 @@
   request.credentials_mode = mojom::CredentialsMode::kOmit;
   request.method = net::HttpRequestHeaders::kGetMethod;
   request.url = url;
-  request.request_initiator = url::Origin::Create(main_world_origin);
-  request.isolated_world_origin = url::Origin::Create(isolated_world_origin);
+  request.request_initiator = main_world_origin;
+  request.isolated_world_origin = isolated_world_origin;
   CreateLoaderAndStart(request);
   RunUntilCreateLoaderAndStartCalled();
 
@@ -1289,7 +1302,7 @@
 
   EXPECT_TRUE(IsNetworkLoaderStarted());
   EXPECT_FALSE(client().has_received_redirect());
-  EXPECT_TRUE(client().has_received_response());
+  ASSERT_TRUE(client().has_received_response());
   EXPECT_EQ(network::mojom::FetchResponseType::kBasic,
             client().response_head()->response_type);
   EXPECT_TRUE(client().has_received_completion());
@@ -1300,18 +1313,22 @@
 // ResourceRequest::isolated_world_origin when consulting OriginAccessList
 // after redirects.
 TEST_F(CorsURLLoaderTest, OriginAccessList_IsolatedWorldOrigin_Redirect) {
-  const GURL main_world_origin("http://main-world.com");
-  const GURL isolated_world_origin("http://isolated-world.com");
+  const url::Origin main_world_origin =
+      url::Origin::Create(GURL("http://main-world.com"));
+  const url::Origin isolated_world_origin =
+      url::Origin::Create(GURL("http://isolated-world.com"));
   const GURL url("http://other.com/foo.png");
   // |new_url| is same-origin as |url| to avoid tainting the response
   // in CorsURLLoader::OnReceiveRedirect.
   const GURL new_url("http://other.com/bar.png");
 
-  AddAllowListEntryForOrigin(url::Origin::Create(isolated_world_origin),
-                             url.scheme(), url.host(),
+  ResetFactory(main_world_origin, kRendererProcessId, false /* trusted */,
+               false /* ignore_isolated_world_origin */);
+
+  AddAllowListEntryForOrigin(isolated_world_origin, url.scheme(), url.host(),
                              mojom::CorsDomainMatchMode::kDisallowSubdomains);
-  AddAllowListEntryForOrigin(url::Origin::Create(isolated_world_origin),
-                             new_url.scheme(), new_url.host(),
+  AddAllowListEntryForOrigin(isolated_world_origin, new_url.scheme(),
+                             new_url.host(),
                              mojom::CorsDomainMatchMode::kDisallowSubdomains);
 
   ResourceRequest request;
@@ -1321,8 +1338,8 @@
   request.credentials_mode = mojom::CredentialsMode::kOmit;
   request.method = net::HttpRequestHeaders::kGetMethod;
   request.url = url;
-  request.request_initiator = url::Origin::Create(main_world_origin);
-  request.isolated_world_origin = url::Origin::Create(isolated_world_origin);
+  request.request_initiator = main_world_origin;
+  request.isolated_world_origin = isolated_world_origin;
   CreateLoaderAndStart(request);
   RunUntilCreateLoaderAndStartCalled();
 
@@ -1342,13 +1359,50 @@
 
   EXPECT_TRUE(IsNetworkLoaderStarted());
   EXPECT_TRUE(client().has_received_redirect());
-  EXPECT_TRUE(client().has_received_response());
+  ASSERT_TRUE(client().has_received_response());
   EXPECT_EQ(network::mojom::FetchResponseType::kBasic,
             client().response_head()->response_type);
   EXPECT_TRUE(client().has_received_completion());
   EXPECT_EQ(net::OK, client().completion_status().error_code);
 }
 
+// Tests if CorsURLLoader takes ignores ResourceRequest::isolated_world_origin
+// when URLLoaderFactoryParams::ignore_isolated_world_origin is set to true.
+TEST_F(CorsURLLoaderTest, OriginAccessList_IsolatedWorldOriginIgnored) {
+  const url::Origin main_world_origin =
+      url::Origin::Create(GURL("http://main-world.com"));
+  const url::Origin isolated_world_origin =
+      url::Origin::Create(GURL("http://isolated-world.com"));
+  const GURL url("http://other.com/foo.png");
+
+  ResetFactory(main_world_origin, kRendererProcessId, false /* trusted */,
+               true /* ignore_isolated_world_origin */);
+
+  AddAllowListEntryForOrigin(isolated_world_origin, url.scheme(), url.host(),
+                             mojom::CorsDomainMatchMode::kDisallowSubdomains);
+
+  ResourceRequest request;
+  request.mode = mojom::RequestMode::kCors;
+  request.credentials_mode = mojom::CredentialsMode::kOmit;
+  request.method = net::HttpRequestHeaders::kGetMethod;
+  request.url = url;
+  request.request_initiator = main_world_origin;
+  request.isolated_world_origin = isolated_world_origin;
+  CreateLoaderAndStart(request);
+  RunUntilCreateLoaderAndStartCalled();
+
+  NotifyLoaderClientOnReceiveResponse();
+  NotifyLoaderClientOnComplete(net::OK);
+
+  RunUntilComplete();
+
+  EXPECT_TRUE(IsNetworkLoaderStarted());
+  EXPECT_FALSE(client().has_received_redirect());
+  EXPECT_FALSE(client().has_received_response());
+  EXPECT_TRUE(client().has_received_completion());
+  EXPECT_EQ(net::ERR_FAILED, client().completion_status().error_code);
+}
+
 // Check if higher-priority block list wins.
 TEST_F(CorsURLLoaderTest, OriginAccessList_Blocked) {
   const GURL origin("http://example.com");
@@ -1956,7 +2010,9 @@
   // Run the test with a trusted URLLoaderFactory as well, to make sure a CORS
   // request is in fact made when using a trusted factory.
   for (bool is_trusted : {false, true}) {
-    ResetFactory(base::nullopt, kRendererProcessId, is_trusted);
+    bool ignore_isolated_world_origin = true;  // This is the default.
+    ResetFactory(base::nullopt, kRendererProcessId, is_trusted,
+                 ignore_isolated_world_origin);
 
     BadMessageTestHelper bad_message_helper;
 
@@ -2002,7 +2058,8 @@
 // Test that when a request has LOAD_RESTRICTED_PREFETCH and a
 // NetworkIsolationKey, CorsURLLoaderFactory does not reject the request.
 TEST_F(CorsURLLoaderTest, RestrictedPrefetchSucceedsWithNIK) {
-  ResetFactory(base::nullopt, kRendererProcessId, true);
+  ResetFactory(base::nullopt, kRendererProcessId, true /* is_trusted */,
+               true /* ignore_isolated_world_origin */);
 
   BadMessageTestHelper bad_message_helper;
 
@@ -2041,7 +2098,8 @@
 // because the LOAD_RESTRICTED_PREFETCH flag must only appear on requests that
 // make use of their TrustedParams' |network_isolation_key|.
 TEST_F(CorsURLLoaderTest, RestrictedPrefetchFailsWithoutNIK) {
-  ResetFactory(base::nullopt, kRendererProcessId, true);
+  ResetFactory(base::nullopt, kRendererProcessId, true /* is_trusted */,
+               true /* ignore_isolated_world_origin */);
 
   BadMessageTestHelper bad_message_helper;
 
diff --git a/services/network/public/mojom/network_context.mojom b/services/network/public/mojom/network_context.mojom
index 32a60d94..c37e71fb 100644
--- a/services/network/public/mojom/network_context.mojom
+++ b/services/network/public/mojom/network_context.mojom
@@ -565,6 +565,11 @@
   // Cross-origin read blocking (CORB) configuration.
   bool is_corb_enabled = true;
 
+  // Whether |isolated_world_origin| from network::ResourceRequest should be
+  // ignored.  Set |ignore_isolated_world_origin| to |false| to allow isolated
+  // worlds to bypass CORS security checks via OriginAccessList.
+  bool ignore_isolated_world_origin = true;
+
   // Indicate whether a request is not from web page ( probably from chrome
   // extension background page ).
   bool unsafe_non_webby_initiator = false;
diff --git a/third_party/android_build_tools/aapt2/README.chromium b/third_party/android_build_tools/aapt2/README.chromium
index 9dd0caad..98cbf2a 100644
--- a/third_party/android_build_tools/aapt2/README.chromium
+++ b/third_party/android_build_tools/aapt2/README.chromium
@@ -12,4 +12,4 @@
 distributed here as a CIPD package instead. See cipd.yaml for details.
 
 Local Modifications:
-Fetched prebuilt from go/aapt2-6089589 (version not yet published to maven).
+Fetched prebuilt from go/aapt2-6143298 (version not yet published to maven).
diff --git a/third_party/blink/public/OWNERS b/third_party/blink/public/OWNERS
index f87e5af..c488ebc 100644
--- a/third_party/blink/public/OWNERS
+++ b/third_party/blink/public/OWNERS
@@ -1,6 +1,7 @@
 chrishtr@chromium.org
 dcheng@chromium.org
 dgozman@chromium.org
+dtapuska@chromium.org
 falken@chromium.org
 foolip@chromium.org
 haraken@chromium.org
diff --git a/third_party/blink/public/mojom/frame/frame.mojom b/third_party/blink/public/mojom/frame/frame.mojom
index 8655fb8..45c10d4 100644
--- a/third_party/blink/public/mojom/frame/frame.mojom
+++ b/third_party/blink/public/mojom/frame/frame.mojom
@@ -174,6 +174,10 @@
   // Provides accessibility information about the termination of a find
   // in page operation.
   HandleAccessibilityFindInPageTermination();
+
+  // Sent after the onload handler has been invoked for the document
+  // in this frame. Sent for top-level frames.
+  DocumentOnLoadCompleted();
 };
 
 // Implemented in Blink, this interface defines frame-specific methods that will
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom
index 200dee4..b123ff61 100644
--- a/third_party/blink/public/mojom/web_feature/web_feature.mojom
+++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -2501,6 +2501,7 @@
   kCSPROWithReasonableRestrictions = 3136,
   kCSPWithBetterThanReasonableRestrictions = 3137,
   kCSPROWithBetterThanReasonableRestrictions = 3138,
+  kMeasureMemory = 3139,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/renderer/core/editing/commands/clipboard_commands.cc b/third_party/blink/renderer/core/editing/commands/clipboard_commands.cc
index ca2eca9..8c8cd1e 100644
--- a/third_party/blink/renderer/core/editing/commands/clipboard_commands.cc
+++ b/third_party/blink/renderer/core/editing/commands/clipboard_commands.cc
@@ -239,9 +239,16 @@
 
   if (HTMLImageElement* image_element =
           ImageElementFromImageDocument(document)) {
-    WriteImageNodeToClipboard(*frame.GetSystemClipboard(), *image_element,
-                              document->title());
-    return true;
+    // In an image document, normally there isn't anything to select, and we
+    // only want to copy the image itself.
+    if (frame.Selection().ComputeVisibleSelectionInDOMTree().IsNone()) {
+      WriteImageNodeToClipboard(*frame.GetSystemClipboard(), *image_element,
+                                document->title());
+      return true;
+    }
+
+    // Scripts may insert other contents into an image document. Falls through
+    // when they are selected.
   }
 
   // Since copy is a read-only operation it succeeds anytime a selection
diff --git a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
index 1139a78..012abf06 100644
--- a/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
+++ b/third_party/blink/renderer/core/exported/local_frame_client_impl.cc
@@ -387,6 +387,8 @@
 }
 
 void LocalFrameClientImpl::DispatchDidHandleOnloadEvents() {
+  if (!web_frame_->Parent())
+    web_frame_->GetFrame()->GetLocalFrameHostRemote().DocumentOnLoadCompleted();
   if (web_frame_->Client())
     web_frame_->Client()->DidHandleOnloadEvents();
 }
diff --git a/third_party/blink/renderer/core/exported/web_frame_serializer.cc b/third_party/blink/renderer/core/exported/web_frame_serializer.cc
index c5f5b6aa..fa35bdf 100644
--- a/third_party/blink/renderer/core/exported/web_frame_serializer.cc
+++ b/third_party/blink/renderer/core/exported/web_frame_serializer.cc
@@ -40,356 +40,23 @@
 #include "third_party/blink/public/web/web_frame_serializer_client.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/element.h"
-#include "third_party/blink/renderer/core/dom/shadow_root.h"
-#include "third_party/blink/renderer/core/exported/web_remote_frame_impl.h"
-#include "third_party/blink/renderer/core/frame/frame.h"
 #include "third_party/blink/renderer/core/frame/frame_serializer.h"
-#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/frame/frame_serializer_delegate_impl.h"
 #include "third_party/blink/renderer/core/frame/local_frame.h"
-#include "third_party/blink/renderer/core/frame/remote_frame.h"
 #include "third_party/blink/renderer/core/frame/web_frame_serializer_impl.h"
 #include "third_party/blink/renderer/core/frame/web_local_frame_impl.h"
-#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
-#include "third_party/blink/renderer/core/html/html_all_collection.h"
-#include "third_party/blink/renderer/core/html/html_frame_element_base.h"
-#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
-#include "third_party/blink/renderer/core/html/html_head_element.h"
-#include "third_party/blink/renderer/core/html/html_image_element.h"
-#include "third_party/blink/renderer/core/html/html_link_element.h"
-#include "third_party/blink/renderer/core/html/html_table_element.h"
-#include "third_party/blink/renderer/core/html_names.h"
-#include "third_party/blink/renderer/core/input_type_names.h"
-#include "third_party/blink/renderer/core/layout/layout_box.h"
-#include "third_party/blink/renderer/core/loader/document_loader.h"
-#include "third_party/blink/renderer/core/loader/frame_loader.h"
-#include "third_party/blink/renderer/core/page/chrome_client.h"
-#include "third_party/blink/renderer/core/page/page.h"
-#include "third_party/blink/renderer/platform/heap/heap.h"
 #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
 #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource_request.h"
-#include "third_party/blink/renderer/platform/loader/fetch/resource_response.h"
 #include "third_party/blink/renderer/platform/mhtml/mhtml_archive.h"
-#include "third_party/blink/renderer/platform/mhtml/mhtml_parser.h"
 #include "third_party/blink/renderer/platform/mhtml/serialized_resource.h"
 #include "third_party/blink/renderer/platform/weborigin/kurl.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 #include "third_party/blink/renderer/platform/wtf/deque.h"
-#include "third_party/blink/renderer/platform/wtf/hash_map.h"
-#include "third_party/blink/renderer/platform/wtf/hash_set.h"
-#include "third_party/blink/renderer/platform/wtf/shared_buffer.h"
 #include "third_party/blink/renderer/platform/wtf/text/string_concatenate.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
 
-namespace {
-
-const int kPopupOverlayZIndexThreshold = 50;
-const char kShadowModeAttributeName[] = "shadowmode";
-const char kShadowDelegatesFocusAttributeName[] = "shadowdelegatesfocus";
-
-// Returns a Content-ID to be used for the given frame.
-// See rfc2557 - section 8.3 - "Use of the Content-ID header and CID URLs".
-// Format note - the returned string should be of the form "<foo@bar.com>"
-// (i.e. the strings should include the angle brackets).
-String GetContentID(Frame* frame) {
-  String frame_id = String(ToTraceValue(frame).data());
-  return "<frame-" + frame_id + "@mhtml.blink>";
-}
-
-class MHTMLFrameSerializerDelegate final : public FrameSerializer::Delegate {
-  STACK_ALLOCATED();
-
- public:
-  MHTMLFrameSerializerDelegate(
-      WebFrameSerializer::MHTMLPartsGenerationDelegate&,
-      HeapHashSet<WeakMember<const Element>>&);
-  ~MHTMLFrameSerializerDelegate() override = default;
-  bool ShouldIgnoreElement(const Element&) override;
-  bool ShouldIgnoreAttribute(const Element&, const Attribute&) override;
-  bool RewriteLink(const Element&, String& rewritten_link) override;
-  bool ShouldSkipResourceWithURL(const KURL&) override;
-  Vector<Attribute> GetCustomAttributes(const Element&) override;
-  std::pair<Node*, Element*> GetAuxiliaryDOMTree(const Element&) const override;
-  bool ShouldCollectProblemMetric() override;
-
- private:
-  bool ShouldIgnoreHiddenElement(const Element&);
-  bool ShouldIgnoreMetaElement(const Element&);
-  bool ShouldIgnorePopupOverlayElement(const Element&);
-  void GetCustomAttributesForImageElement(const HTMLImageElement&,
-                                          Vector<Attribute>*);
-
-  WebFrameSerializer::MHTMLPartsGenerationDelegate& web_delegate_;
-  HeapHashSet<WeakMember<const Element>>& shadow_template_elements_;
-  bool popup_overlays_skipped_;
-
-  DISALLOW_COPY_AND_ASSIGN(MHTMLFrameSerializerDelegate);
-};
-
-MHTMLFrameSerializerDelegate::MHTMLFrameSerializerDelegate(
-    WebFrameSerializer::MHTMLPartsGenerationDelegate& web_delegate,
-    HeapHashSet<WeakMember<const Element>>& shadow_template_elements)
-    : web_delegate_(web_delegate),
-      shadow_template_elements_(shadow_template_elements),
-      popup_overlays_skipped_(false) {}
-
-bool MHTMLFrameSerializerDelegate::ShouldIgnoreElement(const Element& element) {
-  if (ShouldIgnoreHiddenElement(element))
-    return true;
-  if (ShouldIgnoreMetaElement(element))
-    return true;
-  if (web_delegate_.RemovePopupOverlay() &&
-      ShouldIgnorePopupOverlayElement(element)) {
-    return true;
-  }
-  // Remove <link> for stylesheets that do not load.
-  auto* html_link_element = DynamicTo<HTMLLinkElement>(element);
-  if (html_link_element && html_link_element->RelAttribute().IsStyleSheet() &&
-      !html_link_element->sheet()) {
-    return true;
-  }
-  return false;
-}
-
-bool MHTMLFrameSerializerDelegate::ShouldIgnoreHiddenElement(
-    const Element& element) {
-  // If an iframe is in the head, it will be moved to the body when the page is
-  // being loaded. But if an iframe is injected into the head later, it will
-  // stay there and not been displayed. To prevent it from being brought to the
-  // saved page and cause it being displayed, we should not include it.
-  if (IsA<HTMLIFrameElement>(element) &&
-      Traversal<HTMLHeadElement>::FirstAncestor(element)) {
-    return true;
-  }
-
-  // Do not include the element that is marked with hidden attribute.
-  if (element.FastHasAttribute(html_names::kHiddenAttr))
-    return true;
-
-  // Do not include the hidden form element.
-  auto* html_element_element = DynamicTo<HTMLInputElement>(&element);
-  return html_element_element &&
-         html_element_element->type() == input_type_names::kHidden;
-}
-
-bool MHTMLFrameSerializerDelegate::ShouldIgnoreMetaElement(
-    const Element& element) {
-  // Do not include meta elements that declare Content-Security-Policy
-  // directives. They should have already been enforced when the original
-  // document is loaded. Since only the rendered resources are encapsulated in
-  // the saved MHTML page, there is no need to carry the directives. If they
-  // are still kept in the MHTML, child frames that are referred to using cid:
-  // scheme could be prevented from loading.
-  if (!IsA<HTMLMetaElement>(element))
-    return false;
-  if (!element.FastHasAttribute(html_names::kContentAttr))
-    return false;
-  const AtomicString& http_equiv =
-      element.FastGetAttribute(html_names::kHttpEquivAttr);
-  return http_equiv == "Content-Security-Policy";
-}
-
-bool MHTMLFrameSerializerDelegate::ShouldIgnorePopupOverlayElement(
-    const Element& element) {
-  // The element should be visible.
-  LayoutBox* box = element.GetLayoutBox();
-  if (!box)
-    return false;
-
-  // The bounding box of the element should contain center point of the
-  // viewport.
-  LocalDOMWindow* window = element.GetDocument().domWindow();
-  DCHECK(window);
-  int center_x = window->innerWidth() / 2;
-  int center_y = window->innerHeight() / 2;
-  if (Page* page = element.GetDocument().GetPage()) {
-    center_x = page->GetChromeClient().WindowToViewportScalar(
-        window->GetFrame(), center_x);
-    center_y = page->GetChromeClient().WindowToViewportScalar(
-        window->GetFrame(), center_y);
-  }
-  LayoutPoint center_point(center_x, center_y);
-  if (!box->FrameRect().Contains(center_point))
-    return false;
-
-  // The z-index should be greater than the threshold.
-  if (box->Style()->ZIndex() < kPopupOverlayZIndexThreshold)
-    return false;
-
-  popup_overlays_skipped_ = true;
-
-  return true;
-}
-
-bool MHTMLFrameSerializerDelegate::ShouldIgnoreAttribute(
-    const Element& element,
-    const Attribute& attribute) {
-  // TODO(fgorski): Presence of srcset attribute causes MHTML to not display
-  // images, as only the value of src is pulled into the archive. Discarding
-  // srcset prevents the problem. Long term we should make sure to MHTML plays
-  // nicely with srcset.
-  if (IsA<HTMLImageElement>(element) &&
-      (attribute.LocalName() == html_names::kSrcsetAttr ||
-       attribute.LocalName() == html_names::kSizesAttr)) {
-    return true;
-  }
-
-  // Do not save ping attribute since anyway the ping will be blocked from
-  // MHTML.
-  if (IsA<HTMLAnchorElement>(element) &&
-      attribute.LocalName() == html_names::kPingAttr) {
-    return true;
-  }
-
-  // The special attribute in a template element to denote the shadow DOM
-  // should only be generated from MHTML serialization. If it is found in the
-  // original page, it should be ignored.
-  if (IsA<HTMLTemplateElement>(element) &&
-      (attribute.LocalName() == kShadowModeAttributeName ||
-       attribute.LocalName() == kShadowDelegatesFocusAttributeName) &&
-      !shadow_template_elements_.Contains(&element)) {
-    return true;
-  }
-
-  // If srcdoc attribute for frame elements will be rewritten as src attribute
-  // containing link instead of html contents, don't ignore the attribute.
-  // Bail out now to avoid the check in Element::isScriptingAttribute.
-  bool is_src_doc_attribute = IsA<HTMLFrameElementBase>(element) &&
-                              attribute.GetName() == html_names::kSrcdocAttr;
-  String new_link_for_the_element;
-  if (is_src_doc_attribute && RewriteLink(element, new_link_for_the_element))
-    return false;
-
-  //  Drop integrity attribute for those links with subresource loaded.
-  auto* html_link_element = DynamicTo<HTMLLinkElement>(element);
-  if (attribute.LocalName() == html_names::kIntegrityAttr &&
-      html_link_element && html_link_element->sheet()) {
-    return true;
-  }
-
-  // Do not include attributes that contain javascript. This is because the
-  // script will not be executed when a MHTML page is being loaded.
-  return element.IsScriptingAttribute(attribute);
-}
-
-bool MHTMLFrameSerializerDelegate::RewriteLink(const Element& element,
-                                               String& rewritten_link) {
-  auto* frame_owner = DynamicTo<HTMLFrameOwnerElement>(element);
-  if (!frame_owner)
-    return false;
-
-  Frame* frame = frame_owner->ContentFrame();
-  if (!frame)
-    return false;
-
-  WebString content_id = GetContentID(frame);
-  KURL cid_uri = MHTMLParser::ConvertContentIDToURI(content_id);
-  DCHECK(cid_uri.IsValid());
-  rewritten_link = cid_uri.GetString();
-  return true;
-}
-
-bool MHTMLFrameSerializerDelegate::ShouldSkipResourceWithURL(const KURL& url) {
-  return web_delegate_.ShouldSkipResource(url);
-}
-
-Vector<Attribute> MHTMLFrameSerializerDelegate::GetCustomAttributes(
-    const Element& element) {
-  Vector<Attribute> attributes;
-
-  if (auto* image = DynamicTo<HTMLImageElement>(element)) {
-    GetCustomAttributesForImageElement(*image, &attributes);
-  }
-
-  return attributes;
-}
-
-bool MHTMLFrameSerializerDelegate::ShouldCollectProblemMetric() {
-  return web_delegate_.UsePageProblemDetectors();
-}
-
-void MHTMLFrameSerializerDelegate::GetCustomAttributesForImageElement(
-    const HTMLImageElement& element,
-    Vector<Attribute>* attributes) {
-  // Currently only the value of src is pulled into the archive and the srcset
-  // attribute is ignored (see shouldIgnoreAttribute() above). If the device
-  // has a higher DPR, a different image from srcset could be loaded instead.
-  // When this occurs, we should provide the rendering width and height for
-  // <img> element if not set.
-
-  // The image should be loaded and participate the layout.
-  ImageResourceContent* image = element.CachedImage();
-  if (!image || !image->HasImage() || image->ErrorOccurred() ||
-      !element.GetLayoutObject()) {
-    return;
-  }
-
-  // The width and height attributes should not be set.
-  if (element.FastHasAttribute(html_names::kWidthAttr) ||
-      element.FastHasAttribute(html_names::kHeightAttr)) {
-    return;
-  }
-
-  // Check if different image is loaded. naturalWidth/naturalHeight will return
-  // the image size adjusted with current DPR.
-  if (((int)element.naturalWidth()) == image->GetImage()->width() &&
-      ((int)element.naturalHeight()) == image->GetImage()->height()) {
-    return;
-  }
-
-  Attribute width_attribute(html_names::kWidthAttr,
-                            AtomicString::Number(element.LayoutBoxWidth()));
-  attributes->push_back(width_attribute);
-  Attribute height_attribute(html_names::kHeightAttr,
-                             AtomicString::Number(element.LayoutBoxHeight()));
-  attributes->push_back(height_attribute);
-}
-
-std::pair<Node*, Element*> MHTMLFrameSerializerDelegate::GetAuxiliaryDOMTree(
-    const Element& element) const {
-  ShadowRoot* shadow_root = element.GetShadowRoot();
-  if (!shadow_root)
-    return std::pair<Node*, Element*>();
-
-  String shadow_mode;
-  switch (shadow_root->GetType()) {
-    case ShadowRootType::kUserAgent:
-      // No need to serialize.
-      return std::pair<Node*, Element*>();
-    case ShadowRootType::V0:
-      shadow_mode = "v0";
-      break;
-    case ShadowRootType::kOpen:
-      shadow_mode = "open";
-      break;
-    case ShadowRootType::kClosed:
-      shadow_mode = "closed";
-      break;
-  }
-
-  // Put the shadow DOM content inside a template element. A special attribute
-  // is set to tell the mode of the shadow DOM.
-  auto* template_element = MakeGarbageCollected<Element>(
-      html_names::kTemplateTag, &(element.GetDocument()));
-  template_element->setAttribute(
-      QualifiedName(g_null_atom, kShadowModeAttributeName, g_null_atom),
-      AtomicString(shadow_mode));
-  if (shadow_root->GetType() != ShadowRootType::V0 &&
-      shadow_root->delegatesFocus()) {
-    template_element->setAttribute(
-        QualifiedName(g_null_atom, kShadowDelegatesFocusAttributeName,
-                      g_null_atom),
-        g_empty_atom);
-  }
-  shadow_template_elements_.insert(template_element);
-
-  return std::pair<Node*, Element*>(shadow_root, template_element);
-}
-
-}  // namespace
-
 WebThreadSafeData WebFrameSerializer::GenerateMHTMLHeader(
     const WebString& boundary,
     WebLocalFrame* frame,
@@ -432,8 +99,8 @@
     SCOPED_BLINK_UMA_HISTOGRAM_TIMER(
         "PageSerialization.MhtmlGeneration.SerializationTime.SingleFrame");
     HeapHashSet<WeakMember<const Element>> shadow_template_elements;
-    MHTMLFrameSerializerDelegate core_delegate(*web_delegate,
-                                               shadow_template_elements);
+    FrameSerializerDelegateImpl core_delegate(*web_delegate,
+                                              shadow_template_elements);
     FrameSerializer serializer(resources, core_delegate);
     serializer.SerializeFrame(*frame);
   }
@@ -453,9 +120,9 @@
         "PageSerialization.MhtmlGeneration.EncodingTime.SingleFrame");
     // Frame is the 1st resource (see FrameSerializer::serializeFrame doc
     // comment). Frames get a Content-ID header.
-    MHTMLArchive::GenerateMHTMLPart(boundary, GetContentID(frame),
-                                    encoding_policy, resources.TakeFirst(),
-                                    *output->MutableData());
+    MHTMLArchive::GenerateMHTMLPart(
+        boundary, FrameSerializerDelegateImpl::GetContentID(frame),
+        encoding_policy, resources.TakeFirst(), *output->MutableData());
     while (!resources.IsEmpty()) {
       TRACE_EVENT0("page-serialization",
                    "WebFrameSerializer::generateMHTMLParts encoding");
diff --git a/third_party/blink/renderer/core/exported/web_frame_test.cc b/third_party/blink/renderer/core/exported/web_frame_test.cc
index cbeb817..bb2c86c 100644
--- a/third_party/blink/renderer/core/exported/web_frame_test.cc
+++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -103,6 +103,7 @@
 #include "third_party/blink/renderer/core/editing/finder/text_finder.h"
 #include "third_party/blink/renderer/core/editing/frame_selection.h"
 #include "third_party/blink/renderer/core/editing/markers/document_marker_controller.h"
+#include "third_party/blink/renderer/core/editing/selection_template.h"
 #include "third_party/blink/renderer/core/editing/spellcheck/idle_spell_check_controller.h"
 #include "third_party/blink/renderer/core/editing/spellcheck/spell_checker.h"
 #include "third_party/blink/renderer/core/events/mouse_event.h"
@@ -10566,6 +10567,51 @@
   system_clipboard->CommitWrite();
 }
 
+TEST_F(WebFrameTest, CopyTextInImageDocument) {
+  // If Javascript inserts other contents into an image document, we should be
+  // able to copy those contents, not just the image itself.
+
+  RegisterMockedHttpURLLoadWithMimeType("white-1x1.png", "image/png");
+  frame_test_helpers::WebViewHelper web_view_helper;
+  web_view_helper.InitializeAndLoad(base_url_ + "white-1x1.png");
+  WebViewImpl* web_view = web_view_helper.GetWebView();
+  WebLocalFrameImpl* web_frame = web_view->MainFrameImpl();
+  Document* document = web_frame->GetFrame()->GetDocument();
+
+  ASSERT_TRUE(document);
+  EXPECT_TRUE(IsA<ImageDocument>(document));
+
+  Node* text = document->createTextNode("copy me");
+  document->body()->appendChild(text);
+  document->GetFrame()->Selection().SetSelection(
+      SelectionInDOMTree::Builder().SelectAllChildren(*text).Build(),
+      SetSelectionOptions());
+
+  // Setup a mock clipboard host.
+  PageTestBase::MockClipboardHostProvider mock_clipboard_host_provider(
+      web_frame->GetFrame()->GetBrowserInterfaceBroker());
+
+  SystemClipboard* system_clipboard =
+      document->GetFrame()->GetSystemClipboard();
+  ASSERT_TRUE(system_clipboard);
+
+  EXPECT_TRUE(system_clipboard->ReadAvailableTypes().IsEmpty());
+
+  bool result = web_frame->ExecuteCommand("Copy");
+  test::RunPendingTasks();
+
+  EXPECT_TRUE(result);
+
+  Vector<String> types = system_clipboard->ReadAvailableTypes();
+  EXPECT_EQ(2u, types.size());
+  EXPECT_EQ("text/plain", types[0]);
+  EXPECT_EQ("text/html", types[1]);
+
+  // Clear clipboard data
+  system_clipboard->WritePlainText("");
+  system_clipboard->CommitWrite();
+}
+
 class CallbackOrderingWebFrameClient
     : public frame_test_helpers::TestWebFrameClient {
  public:
diff --git a/third_party/blink/renderer/core/exported/web_view_test.cc b/third_party/blink/renderer/core/exported/web_view_test.cc
index 3729bf3b..eed9d1d 100644
--- a/third_party/blink/renderer/core/exported/web_view_test.cc
+++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -4387,7 +4387,6 @@
   WebViewImpl* web_view_;
   frame_test_helpers::WebViewHelper& web_view_helper_;
   frame_test_helpers::TestWebFrameClient web_frame_client_;
-  std::unique_ptr<service_manager::InterfaceProvider::TestApi> test_api_;
 };
 
 // Mock implementation of the UnhandledTapNotifier Mojo receiver, for testing
diff --git a/third_party/blink/renderer/core/frame/BUILD.gn b/third_party/blink/renderer/core/frame/BUILD.gn
index 6ec08d1..cbbfa3c 100644
--- a/third_party/blink/renderer/core/frame/BUILD.gn
+++ b/third_party/blink/renderer/core/frame/BUILD.gn
@@ -75,6 +75,8 @@
     "frame_owner.h",
     "frame_serializer.cc",
     "frame_serializer.h",
+    "frame_serializer_delegate_impl.cc",
+    "frame_serializer_delegate_impl.h",
     "frame_types.h",
     "frame_view.cc",
     "frame_view.h",
diff --git a/third_party/blink/renderer/core/frame/frame_serializer_delegate_impl.cc b/third_party/blink/renderer/core/frame/frame_serializer_delegate_impl.cc
new file mode 100644
index 0000000..ac111ef
--- /dev/null
+++ b/third_party/blink/renderer/core/frame/frame_serializer_delegate_impl.cc
@@ -0,0 +1,320 @@
+// 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/frame/frame_serializer_delegate_impl.h"
+
+#include "third_party/blink/public/web/web_frame_serializer.h"
+#include "third_party/blink/renderer/core/dom/attribute.h"
+#include "third_party/blink/renderer/core/dom/document.h"
+#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/dom/element_traversal.h"
+#include "third_party/blink/renderer/core/dom/shadow_root.h"
+#include "third_party/blink/renderer/core/frame/frame.h"
+#include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/html/forms/html_input_element.h"
+#include "third_party/blink/renderer/core/html/html_anchor_element.h"
+#include "third_party/blink/renderer/core/html/html_frame_element_base.h"
+#include "third_party/blink/renderer/core/html/html_frame_owner_element.h"
+#include "third_party/blink/renderer/core/html/html_head_element.h"
+#include "third_party/blink/renderer/core/html/html_iframe_element.h"
+#include "third_party/blink/renderer/core/html/html_image_element.h"
+#include "third_party/blink/renderer/core/html/html_link_element.h"
+#include "third_party/blink/renderer/core/html/html_meta_element.h"
+#include "third_party/blink/renderer/core/html/html_template_element.h"
+#include "third_party/blink/renderer/core/html/link_rel_attribute.h"
+#include "third_party/blink/renderer/core/html_names.h"
+#include "third_party/blink/renderer/core/input_type_names.h"
+#include "third_party/blink/renderer/core/layout/layout_box.h"
+#include "third_party/blink/renderer/core/layout/layout_object.h"
+#include "third_party/blink/renderer/core/loader/resource/image_resource_content.h"
+#include "third_party/blink/renderer/core/page/chrome_client.h"
+#include "third_party/blink/renderer/core/page/page.h"
+#include "third_party/blink/renderer/platform/geometry/layout_point.h"
+#include "third_party/blink/renderer/platform/geometry/layout_rect.h"
+#include "third_party/blink/renderer/platform/heap/heap.h"
+#include "third_party/blink/renderer/platform/mhtml/mhtml_parser.h"
+#include "third_party/blink/renderer/platform/weborigin/kurl.h"
+#include "third_party/blink/renderer/platform/wtf/assertions.h"
+#include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
+
+namespace blink {
+
+namespace {
+
+const int kPopupOverlayZIndexThreshold = 50;
+const char kShadowModeAttributeName[] = "shadowmode";
+const char kShadowDelegatesFocusAttributeName[] = "shadowdelegatesfocus";
+
+}  // namespace
+
+// static
+String FrameSerializerDelegateImpl::GetContentID(Frame* frame) {
+  DCHECK(frame);
+  String frame_id = String(frame->ToTraceValue().data());
+  return "<frame-" + frame_id + "@mhtml.blink>";
+}
+
+FrameSerializerDelegateImpl::FrameSerializerDelegateImpl(
+    WebFrameSerializer::MHTMLPartsGenerationDelegate& web_delegate,
+    HeapHashSet<WeakMember<const Element>>& shadow_template_elements)
+    : web_delegate_(web_delegate),
+      shadow_template_elements_(shadow_template_elements),
+      popup_overlays_skipped_(false) {}
+
+bool FrameSerializerDelegateImpl::ShouldIgnoreElement(const Element& element) {
+  if (ShouldIgnoreHiddenElement(element))
+    return true;
+  if (ShouldIgnoreMetaElement(element))
+    return true;
+  if (web_delegate_.RemovePopupOverlay() &&
+      ShouldIgnorePopupOverlayElement(element)) {
+    return true;
+  }
+  // Remove <link> for stylesheets that do not load.
+  auto* html_link_element = DynamicTo<HTMLLinkElement>(element);
+  if (html_link_element && html_link_element->RelAttribute().IsStyleSheet() &&
+      !html_link_element->sheet()) {
+    return true;
+  }
+  return false;
+}
+
+bool FrameSerializerDelegateImpl::ShouldIgnoreHiddenElement(
+    const Element& element) {
+  // If an iframe is in the head, it will be moved to the body when the page is
+  // being loaded. But if an iframe is injected into the head later, it will
+  // stay there and not been displayed. To prevent it from being brought to the
+  // saved page and cause it being displayed, we should not include it.
+  if (IsA<HTMLIFrameElement>(element) &&
+      Traversal<HTMLHeadElement>::FirstAncestor(element)) {
+    return true;
+  }
+
+  // Do not include the element that is marked with hidden attribute.
+  if (element.FastHasAttribute(html_names::kHiddenAttr))
+    return true;
+
+  // Do not include the hidden form element.
+  auto* html_element_element = DynamicTo<HTMLInputElement>(&element);
+  return html_element_element &&
+         html_element_element->type() == input_type_names::kHidden;
+}
+
+bool FrameSerializerDelegateImpl::ShouldIgnoreMetaElement(
+    const Element& element) {
+  // Do not include meta elements that declare Content-Security-Policy
+  // directives. They should have already been enforced when the original
+  // document is loaded. Since only the rendered resources are encapsulated in
+  // the saved MHTML page, there is no need to carry the directives. If they
+  // are still kept in the MHTML, child frames that are referred to using cid:
+  // scheme could be prevented from loading.
+  if (!IsA<HTMLMetaElement>(element))
+    return false;
+  if (!element.FastHasAttribute(html_names::kContentAttr))
+    return false;
+  const AtomicString& http_equiv =
+      element.FastGetAttribute(html_names::kHttpEquivAttr);
+  return http_equiv == "Content-Security-Policy";
+}
+
+bool FrameSerializerDelegateImpl::ShouldIgnorePopupOverlayElement(
+    const Element& element) {
+  // The element should be visible.
+  LayoutBox* box = element.GetLayoutBox();
+  if (!box)
+    return false;
+
+  // The bounding box of the element should contain center point of the
+  // viewport.
+  LocalDOMWindow* window = element.GetDocument().domWindow();
+  DCHECK(window);
+  int center_x = window->innerWidth() / 2;
+  int center_y = window->innerHeight() / 2;
+  if (Page* page = element.GetDocument().GetPage()) {
+    center_x = page->GetChromeClient().WindowToViewportScalar(
+        window->GetFrame(), center_x);
+    center_y = page->GetChromeClient().WindowToViewportScalar(
+        window->GetFrame(), center_y);
+  }
+  LayoutPoint center_point(center_x, center_y);
+  if (!box->FrameRect().Contains(center_point))
+    return false;
+
+  // The z-index should be greater than the threshold.
+  if (box->Style()->ZIndex() < kPopupOverlayZIndexThreshold)
+    return false;
+
+  popup_overlays_skipped_ = true;
+
+  return true;
+}
+
+bool FrameSerializerDelegateImpl::ShouldIgnoreAttribute(
+    const Element& element,
+    const Attribute& attribute) {
+  // TODO(fgorski): Presence of srcset attribute causes MHTML to not display
+  // images, as only the value of src is pulled into the archive. Discarding
+  // srcset prevents the problem. Long term we should make sure to MHTML plays
+  // nicely with srcset.
+  if (IsA<HTMLImageElement>(element) &&
+      (attribute.LocalName() == html_names::kSrcsetAttr ||
+       attribute.LocalName() == html_names::kSizesAttr)) {
+    return true;
+  }
+
+  // Do not save ping attribute since anyway the ping will be blocked from
+  // MHTML.
+  if (IsA<HTMLAnchorElement>(element) &&
+      attribute.LocalName() == html_names::kPingAttr) {
+    return true;
+  }
+
+  // The special attribute in a template element to denote the shadow DOM
+  // should only be generated from MHTML serialization. If it is found in the
+  // original page, it should be ignored.
+  if (IsA<HTMLTemplateElement>(element) &&
+      (attribute.LocalName() == kShadowModeAttributeName ||
+       attribute.LocalName() == kShadowDelegatesFocusAttributeName) &&
+      !shadow_template_elements_.Contains(&element)) {
+    return true;
+  }
+
+  // If srcdoc attribute for frame elements will be rewritten as src attribute
+  // containing link instead of html contents, don't ignore the attribute.
+  // Bail out now to avoid the check in Element::isScriptingAttribute.
+  bool is_src_doc_attribute = IsA<HTMLFrameElementBase>(element) &&
+                              attribute.GetName() == html_names::kSrcdocAttr;
+  String new_link_for_the_element;
+  if (is_src_doc_attribute && RewriteLink(element, new_link_for_the_element))
+    return false;
+
+  //  Drop integrity attribute for those links with subresource loaded.
+  auto* html_link_element = DynamicTo<HTMLLinkElement>(element);
+  if (attribute.LocalName() == html_names::kIntegrityAttr &&
+      html_link_element && html_link_element->sheet()) {
+    return true;
+  }
+
+  // Do not include attributes that contain javascript. This is because the
+  // script will not be executed when a MHTML page is being loaded.
+  return element.IsScriptingAttribute(attribute);
+}
+
+bool FrameSerializerDelegateImpl::RewriteLink(const Element& element,
+                                              String& rewritten_link) {
+  auto* frame_owner = DynamicTo<HTMLFrameOwnerElement>(element);
+  if (!frame_owner)
+    return false;
+
+  Frame* frame = frame_owner->ContentFrame();
+  if (!frame)
+    return false;
+
+  WebString content_id = GetContentID(frame);
+  KURL cid_uri = MHTMLParser::ConvertContentIDToURI(content_id);
+  DCHECK(cid_uri.IsValid());
+  rewritten_link = cid_uri.GetString();
+  return true;
+}
+
+bool FrameSerializerDelegateImpl::ShouldSkipResourceWithURL(const KURL& url) {
+  return web_delegate_.ShouldSkipResource(url);
+}
+
+Vector<Attribute> FrameSerializerDelegateImpl::GetCustomAttributes(
+    const Element& element) {
+  Vector<Attribute> attributes;
+
+  if (auto* image = DynamicTo<HTMLImageElement>(element)) {
+    GetCustomAttributesForImageElement(*image, &attributes);
+  }
+
+  return attributes;
+}
+
+bool FrameSerializerDelegateImpl::ShouldCollectProblemMetric() {
+  return web_delegate_.UsePageProblemDetectors();
+}
+
+void FrameSerializerDelegateImpl::GetCustomAttributesForImageElement(
+    const HTMLImageElement& element,
+    Vector<Attribute>* attributes) {
+  // Currently only the value of src is pulled into the archive and the srcset
+  // attribute is ignored (see shouldIgnoreAttribute() above). If the device
+  // has a higher DPR, a different image from srcset could be loaded instead.
+  // When this occurs, we should provide the rendering width and height for
+  // <img> element if not set.
+
+  // The image should be loaded and participate the layout.
+  ImageResourceContent* image = element.CachedImage();
+  if (!image || !image->HasImage() || image->ErrorOccurred() ||
+      !element.GetLayoutObject()) {
+    return;
+  }
+
+  // The width and height attributes should not be set.
+  if (element.FastHasAttribute(html_names::kWidthAttr) ||
+      element.FastHasAttribute(html_names::kHeightAttr)) {
+    return;
+  }
+
+  // Check if different image is loaded. naturalWidth/naturalHeight will return
+  // the image size adjusted with current DPR.
+  if ((static_cast<int>(element.naturalWidth())) ==
+          image->GetImage()->width() &&
+      (static_cast<int>(element.naturalHeight())) ==
+          image->GetImage()->height()) {
+    return;
+  }
+
+  Attribute width_attribute(html_names::kWidthAttr,
+                            AtomicString::Number(element.LayoutBoxWidth()));
+  attributes->push_back(width_attribute);
+  Attribute height_attribute(html_names::kHeightAttr,
+                             AtomicString::Number(element.LayoutBoxHeight()));
+  attributes->push_back(height_attribute);
+}
+
+std::pair<Node*, Element*> FrameSerializerDelegateImpl::GetAuxiliaryDOMTree(
+    const Element& element) const {
+  ShadowRoot* shadow_root = element.GetShadowRoot();
+  if (!shadow_root)
+    return std::pair<Node*, Element*>();
+
+  String shadow_mode;
+  switch (shadow_root->GetType()) {
+    case ShadowRootType::kUserAgent:
+      // No need to serialize.
+      return std::pair<Node*, Element*>();
+    case ShadowRootType::V0:
+      shadow_mode = "v0";
+      break;
+    case ShadowRootType::kOpen:
+      shadow_mode = "open";
+      break;
+    case ShadowRootType::kClosed:
+      shadow_mode = "closed";
+      break;
+  }
+
+  // Put the shadow DOM content inside a template element. A special attribute
+  // is set to tell the mode of the shadow DOM.
+  auto* template_element = MakeGarbageCollected<Element>(
+      html_names::kTemplateTag, &(element.GetDocument()));
+  template_element->setAttribute(
+      QualifiedName(g_null_atom, kShadowModeAttributeName, g_null_atom),
+      AtomicString(shadow_mode));
+  if (shadow_root->GetType() != ShadowRootType::V0 &&
+      shadow_root->delegatesFocus()) {
+    template_element->setAttribute(
+        QualifiedName(g_null_atom, kShadowDelegatesFocusAttributeName,
+                      g_null_atom),
+        g_empty_atom);
+  }
+  shadow_template_elements_.insert(template_element);
+
+  return std::pair<Node*, Element*>(shadow_root, template_element);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/frame/frame_serializer_delegate_impl.h b/third_party/blink/renderer/core/frame/frame_serializer_delegate_impl.h
new file mode 100644
index 0000000..d9c82cf
--- /dev/null
+++ b/third_party/blink/renderer/core/frame/frame_serializer_delegate_impl.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 THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FRAME_SERIALIZER_DELEGATE_IMPL_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FRAME_SERIALIZER_DELEGATE_IMPL_H_
+
+#include "third_party/blink/renderer/core/frame/frame_serializer.h"
+
+#include "third_party/blink/public/web/web_frame_serializer.h"
+#include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/platform/heap/heap_allocator.h"
+#include "third_party/blink/renderer/platform/heap/member.h"
+
+namespace blink {
+
+class Frame;
+class KURL;
+class HTMLImageElement;
+
+// An implementation of FrameSerializer's delegate which is used to serialize a
+// frame to a MHTML file.
+class FrameSerializerDelegateImpl final : public FrameSerializer::Delegate {
+  STACK_ALLOCATED();
+
+ public:
+  // Returns a Content-ID to be used for the given frame.
+  // See rfc2557 - section 8.3 - "Use of the Content-ID header and CID URLs".
+  // Format note - the returned string should be of the form "<foo@bar.com>"
+  // (i.e. the strings should include the angle brackets).
+  static String GetContentID(Frame* frame);
+
+  FrameSerializerDelegateImpl(WebFrameSerializer::MHTMLPartsGenerationDelegate&,
+                              HeapHashSet<WeakMember<const Element>>&);
+  ~FrameSerializerDelegateImpl() override = default;
+
+  // FrameSerializer::Delegate implementation.
+  bool ShouldIgnoreElement(const Element&) override;
+  bool ShouldIgnoreAttribute(const Element&, const Attribute&) override;
+  bool RewriteLink(const Element&, String& rewritten_link) override;
+  bool ShouldSkipResourceWithURL(const KURL&) override;
+  Vector<Attribute> GetCustomAttributes(const Element&) override;
+  std::pair<Node*, Element*> GetAuxiliaryDOMTree(const Element&) const override;
+  bool ShouldCollectProblemMetric() override;
+
+ private:
+  bool ShouldIgnoreHiddenElement(const Element&);
+  bool ShouldIgnoreMetaElement(const Element&);
+  bool ShouldIgnorePopupOverlayElement(const Element&);
+  void GetCustomAttributesForImageElement(const HTMLImageElement&,
+                                          Vector<Attribute>*);
+
+  WebFrameSerializer::MHTMLPartsGenerationDelegate& web_delegate_;
+  HeapHashSet<WeakMember<const Element>>& shadow_template_elements_;
+  bool popup_overlays_skipped_;
+
+  DISALLOW_COPY_AND_ASSIGN(FrameSerializerDelegateImpl);
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_FRAME_FRAME_SERIALIZER_DELEGATE_IMPL_H_
diff --git a/third_party/blink/renderer/core/frame/frame_test_helpers.cc b/third_party/blink/renderer/core/frame/frame_test_helpers.cc
index f4d7c97..a6b662c 100644
--- a/third_party/blink/renderer/core/frame/frame_test_helpers.cc
+++ b/third_party/blink/renderer/core/frame/frame_test_helpers.cc
@@ -505,8 +505,7 @@
 int TestWebFrameClient::loads_in_progress_ = 0;
 
 TestWebFrameClient::TestWebFrameClient()
-    : interface_provider_(new service_manager::InterfaceProvider()),
-      associated_interface_provider_(new AssociatedInterfaceProvider(nullptr)),
+    : associated_interface_provider_(new AssociatedInterfaceProvider(nullptr)),
       effective_connection_type_(WebEffectiveConnectionType::kTypeUnknown) {}
 
 TestWebFrameClient::~TestWebFrameClient() = default;
diff --git a/third_party/blink/renderer/core/frame/frame_test_helpers.h b/third_party/blink/renderer/core/frame/frame_test_helpers.h
index 2e79f20f..40f058e3 100644
--- a/third_party/blink/renderer/core/frame/frame_test_helpers.h
+++ b/third_party/blink/renderer/core/frame/frame_test_helpers.h
@@ -42,7 +42,6 @@
 #include "cc/trees/layer_tree_host.h"
 #include "content/renderer/compositor/layer_tree_view.h"
 #include "content/test/stub_layer_tree_view_delegate.h"
-#include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/blink/public/common/frame/frame_owner_element_type.h"
 #include "third_party/blink/public/common/input/web_mouse_event.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_request.mojom-blink-forward.h"
@@ -440,9 +439,6 @@
                                   FrameOwnerElementType) override;
   void DidStartLoading() override;
   void DidStopLoading() override;
-  service_manager::InterfaceProvider* GetInterfaceProvider() override {
-    return interface_provider_.get();
-  }
   std::unique_ptr<blink::WebURLLoaderFactory> CreateURLLoaderFactory()
       override {
     // TODO(kinuko,toyoshim): Stop using Platform's URLLoaderFactory, but create
@@ -469,10 +465,6 @@
   // If set to a non-null value, self-deletes on frame detach.
   std::unique_ptr<TestWebFrameClient> self_owned_;
 
-  // Use service_manager::InterfaceProvider::TestApi to provide test interfaces
-  // through this client.
-  std::unique_ptr<service_manager::InterfaceProvider> interface_provider_;
-
   std::unique_ptr<AssociatedInterfaceProvider> associated_interface_provider_;
 
   // This is null from when the client is created until it is initialized with
diff --git a/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc b/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc
index a14c555..37c8f491 100644
--- a/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc
+++ b/third_party/blink/renderer/core/html/lazy_load_image_observer_test.cc
@@ -544,6 +544,7 @@
       kViewportHeight + GetLoadingDistanceThreshold() - 100));
 
   css_resource.Complete("img { width: 50px; height: 50px; }");
+  test::RunPendingTasks();
 
   Vector<char> full_image = ReadTestImage();
   ASSERT_LT(2048U, full_image.size());
@@ -677,6 +678,7 @@
       kViewportHeight + GetLoadingDistanceThreshold() + 100));
 
   css_resource.Complete("img { width: 50px; height: 50px; }");
+  test::RunPendingTasks();
 
   Compositor().BeginFrame();
   test::RunPendingTasks();
diff --git a/third_party/blink/renderer/core/mojo/mojo.idl b/third_party/blink/renderer/core/mojo/mojo.idl
index 9bfcfc6..6a9e639 100644
--- a/third_party/blink/renderer/core/mojo/mojo.idl
+++ b/third_party/blink/renderer/core/mojo/mojo.idl
@@ -7,14 +7,14 @@
 typedef unsigned long MojoResult;
 
 enum MojoScope {
-  // Refers to the InterfaceProvider associated with the current execution
+  // Refers to the BrowserInterfaceBroker associated with the current execution
   // context. Either a Document or WorkerGlobalScope.
   "context",
-  // Refers to the InterfaceProvider of the current process.
+  // Refers to the BrowserInterfaceBroker of the current process.
   //
   // Note: A "process" is not a web concept. In some cases the browser process
   // concept of a "site instance" may be useful however there is currently no
-  // InterfaceProvider per site instance.
+  // BrowserInterfaceBroker per site instance.
   "process",
 };
 
diff --git a/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.cc b/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.cc
index 473044db..a32a6d7 100644
--- a/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.cc
+++ b/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.cc
@@ -4,7 +4,6 @@
 
 #include "third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.h"
 
-#include "services/service_manager/public/cpp/interface_provider.h"
 #include "third_party/blink/public/common/browser_interface_broker_proxy.h"
 #include "third_party/blink/public/common/thread_safe_browser_interface_broker_proxy.h"
 #include "third_party/blink/public/platform/platform.h"
@@ -84,32 +83,7 @@
           "Interface " + interface_name_ +
               " is already intercepted by another MojoInterfaceInterceptor.");
     }
-    return;
   }
-
-  // TODO(crbug.com/994843): remove when no longer used.
-  service_manager::InterfaceProvider* interface_provider =
-      GetInterfaceProvider();
-  if (!interface_provider) {
-    exception_state.ThrowDOMException(DOMExceptionCode::kInvalidStateError,
-                                      "The interface provider is unavailable.");
-    return;
-  }
-
-  service_manager::InterfaceProvider::TestApi test_api(interface_provider);
-  if (test_api.HasBinderForName(interface_name)) {
-    exception_state.ThrowDOMException(
-        DOMExceptionCode::kInvalidModificationError,
-        "Interface " + interface_name_ +
-            " is already intercepted by another MojoInterfaceInterceptor.");
-    return;
-  }
-
-  started_ = true;
-  test_api.SetBinderForName(
-      interface_name,
-      WTF::BindRepeating(&MojoInterfaceInterceptor::OnInterfaceRequest,
-                         WrapWeakPersistent(this)));
 }
 
 void MojoInterfaceInterceptor::stop() {
@@ -130,15 +104,7 @@
     DCHECK(context);
     context->GetBrowserInterfaceBroker().SetBinderForTesting(interface_name,
                                                              {});
-    return;
   }
-
-  // TODO(crbug.com/994843): remove when no longer used.
-  // GetInterfaceProvider() is guaranteed not to return nullptr because this
-  // method is called when the context is destroyed.
-  service_manager::InterfaceProvider::TestApi test_api(GetInterfaceProvider());
-  DCHECK(test_api.HasBinderForName(interface_name));
-  test_api.ClearBinderForName(interface_name);
 }
 
 void MojoInterfaceInterceptor::Trace(blink::Visitor* visitor) {
@@ -172,19 +138,10 @@
       process_scope_(process_scope),
       use_browser_interface_broker_(use_browser_interface_broker) {}
 
-service_manager::InterfaceProvider*
-MojoInterfaceInterceptor::GetInterfaceProvider() const {
-  ExecutionContext* context = GetExecutionContext();
-  if (!context)
-    return nullptr;
-
-  return context->GetInterfaceProvider();
-}
-
 void MojoInterfaceInterceptor::OnInterfaceRequest(
     mojo::ScopedMessagePipeHandle handle) {
   // Execution of JavaScript may be forbidden in this context as this method is
-  // called synchronously by the InterfaceProvider. Dispatching of the
+  // called synchronously by the BrowserInterfaceBroker. Dispatching of the
   // 'interfacerequest' event is therefore scheduled to take place in the next
   // microtask. This also more closely mirrors the behavior when an interface
   // request is being satisfied by another process.
diff --git a/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.h b/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.h
index 010d146..ab2f0ac 100644
--- a/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.h
+++ b/third_party/blink/renderer/core/mojo/test/mojo_interface_interceptor.h
@@ -14,10 +14,6 @@
 #include "third_party/blink/renderer/platform/bindings/script_wrappable.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
 
-namespace service_manager {
-class InterfaceProvider;
-}
-
 namespace blink {
 
 class ExceptionState;
@@ -70,7 +66,6 @@
   void ContextDestroyed(ExecutionContext*) final;
 
  private:
-  service_manager::InterfaceProvider* GetInterfaceProvider() const;
   void OnInterfaceRequest(mojo::ScopedMessagePipeHandle);
   void DispatchInterfaceRequestEvent(mojo::ScopedMessagePipeHandle);
 
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
index c77f16d..7caac9d 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.cc
@@ -188,14 +188,10 @@
 CompositedLayerMapping::CompositedLayerMapping(PaintLayer& layer)
     : owning_layer_(layer),
       pending_update_scope_(kGraphicsLayerUpdateNone),
-      is_main_frame_layout_view_layer_(false),
       scrolling_contents_are_empty_(false),
       background_paints_onto_scrolling_contents_layer_(false),
       background_paints_onto_graphics_layer_(false),
       draws_background_onto_content_layer_(false) {
-  if (layer.IsRootLayer() && GetLayoutObject().GetFrame()->IsMainFrame())
-    is_main_frame_layout_view_layer_ = true;
-
   CreatePrimaryGraphicsLayer();
 }
 
diff --git a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
index 83253fe..5514175 100644
--- a/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
+++ b/third_party/blink/renderer/core/paint/compositing/composited_layer_mapping.h
@@ -482,7 +482,6 @@
   PhysicalRect composited_bounds_;
 
   unsigned pending_update_scope_ : 2;
-  unsigned is_main_frame_layout_view_layer_ : 1;
 
   unsigned scrolling_contents_are_empty_ : 1;
 
diff --git a/third_party/blink/renderer/core/testing/fake_local_frame_host.cc b/third_party/blink/renderer/core/testing/fake_local_frame_host.cc
index 5fe8f78..611df97 100644
--- a/third_party/blink/renderer/core/testing/fake_local_frame_host.cc
+++ b/third_party/blink/renderer/core/testing/fake_local_frame_host.cc
@@ -92,4 +92,6 @@
 
 void FakeLocalFrameHost::HandleAccessibilityFindInPageTermination() {}
 
+void FakeLocalFrameHost::DocumentOnLoadCompleted() {}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/testing/fake_local_frame_host.h b/third_party/blink/renderer/core/testing/fake_local_frame_host.h
index ae96d5c..3e789d9 100644
--- a/third_party/blink/renderer/core/testing/fake_local_frame_host.h
+++ b/third_party/blink/renderer/core/testing/fake_local_frame_host.h
@@ -59,6 +59,7 @@
   void HandleAccessibilityFindInPageResult(
       mojom::blink::FindInPageResultAXParamsPtr params) override;
   void HandleAccessibilityFindInPageTermination() override;
+  void DocumentOnLoadCompleted() override;
 
  private:
   void BindFrameHostReceiver(mojo::ScopedInterfaceEndpointHandle handle);
diff --git a/third_party/blink/renderer/core/testing/page_test_base.h b/third_party/blink/renderer/core/testing/page_test_base.h
index 8b0f0036..76aaa7c 100644
--- a/third_party/blink/renderer/core/testing/page_test_base.h
+++ b/third_party/blink/renderer/core/testing/page_test_base.h
@@ -45,7 +45,6 @@
     void BindClipboardHost(mojo::ScopedMessagePipeHandle handle);
 
     MockClipboardHost host_;
-    std::unique_ptr<service_manager::InterfaceProvider::TestApi> clipboard_api_;
   };
 
   PageTestBase();
diff --git a/third_party/blink/renderer/core/timing/performance.idl b/third_party/blink/renderer/core/timing/performance.idl
index 95bec9b..e618c4a 100644
--- a/third_party/blink/renderer/core/timing/performance.idl
+++ b/third_party/blink/renderer/core/timing/performance.idl
@@ -71,7 +71,7 @@
     // https://groups.google.com/a/chromium.org/d/msg/blink-dev/g5YRCGpC9vs/b4OJz71NmPwJ
     [Exposed=Window, Measure] readonly attribute MemoryInfo memory;
 
-    [Exposed=(Window,Worker), CallWith=ScriptState, RuntimeEnabled=MeasureMemory, RaisesException] Promise<MeasureMemory> measureMemory(optional MeasureMemoryOptions options = {});
+    [MeasureAs=MeasureMemory, Exposed=(Window,Worker), CallWith=ScriptState, RuntimeEnabled=MeasureMemory, RaisesException] Promise<MeasureMemory> measureMemory(optional MeasureMemoryOptions options = {});
 
     // JS Self-Profiling API
     // https://github.com/WICG/js-self-profiling/
diff --git a/third_party/blink/renderer/platform/audio/fft_frame.h b/third_party/blink/renderer/platform/audio/fft_frame.h
index ea19c80fd0..bfd2abd 100644
--- a/third_party/blink/renderer/platform/audio/fft_frame.h
+++ b/third_party/blink/renderer/platform/audio/fft_frame.h
@@ -38,13 +38,13 @@
 #include "third_party/blink/renderer/platform/wtf/forward.h"
 #include "third_party/blink/renderer/platform/wtf/threading.h"
 
-#if defined(OS_MACOSX)
-#include <Accelerate/Accelerate.h>
-#elif defined(WTF_USE_WEBAUDIO_FFMPEG)
+#if defined(WTF_USE_WEBAUDIO_FFMPEG)
 struct RDFTContext;
 #elif defined(WTF_USE_WEBAUDIO_PFFFT)
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 #include "third_party/pffft/src/pffft.h"
+#elif defined(OS_MACOSX)
+#include <Accelerate/Accelerate.h>
 #endif
 
 namespace blink {
@@ -144,7 +144,7 @@
   AudioFloatArray real_data_;
   AudioFloatArray imag_data_;
 
-#if defined(OS_MACOSX)
+#if defined(OS_MACOSX) && !defined(WTF_USE_WEBAUDIO_PFFFT)
   // Thin wrapper around FFTSetup so we can call the appropriate routines to
   // construct or release the FFTSetup objects.
   class FFTSetupDatum {
diff --git a/third_party/blink/renderer/platform/audio/mac/fft_frame_mac.cc b/third_party/blink/renderer/platform/audio/mac/fft_frame_mac.cc
index f189a78..3315687 100644
--- a/third_party/blink/renderer/platform/audio/mac/fft_frame_mac.cc
+++ b/third_party/blink/renderer/platform/audio/mac/fft_frame_mac.cc
@@ -30,7 +30,7 @@
 
 #include "build/build_config.h"
 
-#if defined(OS_MACOSX)
+#if defined(OS_MACOSX) && !defined(WTF_USE_WEBAUDIO_PFFFT)
 
 #include "third_party/blink/renderer/platform/audio/fft_frame.h"
 #include "third_party/blink/renderer/platform/audio/hrtf_panner.h"
@@ -201,4 +201,4 @@
 
 }  // namespace blink
 
-#endif  // #if defined(OS_MACOSX)
+#endif  // #if defined(OS_MACOSX) && !defined(WTF_USE_WEBAUDIO_PFFFT)
diff --git a/third_party/blink/web_tests/FlagExpectations/composite-after-paint b/third_party/blink/web_tests/FlagExpectations/composite-after-paint
index 15b18a8..c2d1863f 100644
--- a/third_party/blink/web_tests/FlagExpectations/composite-after-paint
+++ b/third_party/blink/web_tests/FlagExpectations/composite-after-paint
@@ -148,7 +148,9 @@
 # Text failures due to layerization differences
 css3/blending/mix-blend-mode-isolation-remove.html [ Failure ]
 
-virtual/threaded/fast/events/pinch/scroll-visual-viewport-send-boundary-events.html [ Timeout ]
+# Passes on bot, timeouts locally.
+virtual/threaded/fast/events/pinch/scroll-visual-viewport-send-boundary-events.html [ Pass Timeout ]
+
 virtual/threaded/compositing/visibility/layer-visible-content.html [ Failure ]
 
 crbug.com/931486 compositing/overflow/overlap-testing-ancestor-scroller-high-dpi.html [ Failure ]
@@ -217,37 +219,3 @@
 crbug.com/1041322 virtual/threaded/synthetic_gestures/synthetic-pinch-zoom-gesture-touchscreen-zoom-out-slow.html [ Crash ]
 crbug.com/1041322 virtual/threaded/synthetic_gestures/synthetic-pinch-zoom-gesture-touchscreen.html [ Crash ]
 
-# TODO(iopopesc) these need to be rebaselined for FormControlsRefresh focus ring.
-crbug.com/1035582 fast/forms/calendar-picker/calendar-picker-appearance-zoom125.html [ Failure ]
-crbug.com/1035582 fast/forms/select-popup/popup-menu-appearance-long.html [ Failure ]
-crbug.com/1035582 fast/forms/select-popup/popup-menu-appearance-many.html [ Failure ]
-crbug.com/1035582 fast/forms/select-popup/popup-menu-appearance-rtl-default.html [ Failure ]
-crbug.com/1035582 fast/forms/select-popup/popup-menu-appearance-rtl.html [ Failure ]
-crbug.com/1035582 fast/forms/select/listbox-appearance-basic.html [ Failure ]
-crbug.com/1035582 paint/invalidation/4776765.html [ Failure ]
-crbug.com/1035582 paint/invalidation/clip/caret-ancestor-clip-change.html [ Failure ]
-crbug.com/1035582 paint/invalidation/forms/button-reset-focus-by-mouse-then-keydown.html [ Failure ]
-crbug.com/1035582 paint/invalidation/forms/checkbox-focus-by-mouse-then-keydown.html [ Failure ]
-crbug.com/1035582 paint/invalidation/forms/radio-focus-by-mouse-then-keydown.html [ Failure ]
-crbug.com/1035582 paint/invalidation/forms/submit-focus-by-mouse-then-keydown.html [ Failure ]
-crbug.com/1035582 paint/invalidation/forms/textarea-caret.html [ Failure ]
-crbug.com/1035582 paint/invalidation/invalidate-caret-before-text-node-update.html [ Failure ]
-crbug.com/1035582 paint/invalidation/outline/focus-continuations.html [ Failure ]
-crbug.com/1035582 paint/invalidation/outline/focus-enable-continuations.html [ Failure ]
-crbug.com/1035582 paint/invalidation/outline/focus-ring-on-continuation-move.html [ Failure ]
-crbug.com/1035582 paint/invalidation/outline/focus-ring-on-inline-continuation-move.html [ Failure ]
-crbug.com/1035582 paint/invalidation/outline/outline-become-affected-by-descendant.html [ Failure ]
-crbug.com/1035582 paint/invalidation/outline/outline-become-not-affected-by-descendant.html [ Failure ]
-crbug.com/1035582 paint/invalidation/scroll/invalidate-caret-in-composited-scrolling-container.html [ Failure ]
-crbug.com/1035582 paint/invalidation/scroll/invalidate-caret-in-non-composited-scrolling-container.html [ Failure ]
-crbug.com/1035582 paint/invalidation/selection/selection-in-composited-scrolling-container.html [ Failure ]
-crbug.com/1035582 paint/invalidation/selection/selection-in-non-composited-scrolling-container.html [ Failure ]
-crbug.com/1035582 paint/invalidation/svg/focus-element.html [ Failure ]
-crbug.com/1035582 paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem.html [ Failure ]
-crbug.com/1035582 paint/invalidation/svg/transform-focus-ring-repaint.html [ Failure ]
-crbug.com/1035582 paint/invalidation/table/caret-contenteditable-content-after.html [ Failure ]
-crbug.com/1035582 virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance.html [ Failure ]
-crbug.com/1035582 virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance.html [ Failure ]
-crbug.com/1035582 virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi.html [ Failure ]
-
-external/wpt/css/compositing/root-element-blend-mode.html [ Failure ]
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index ec41473..70a3b6a8 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -53,7 +53,6 @@
 crbug.com/1014421 external/wpt/css/cssom-view/MediaQueryList-addListener-handleEvent.html [ Timeout ]
 
 # Tested by paint/background/root-element-background-transparency.html for now.
-external/wpt/css/compositing/root-element-background-transparency.html [ Failure ]
 
 # ====== Site Isolation failures from here ======
 # See also third_party/blink/web_tests/virtual/not-site-per-process/README.md
@@ -374,6 +373,8 @@
 
 crbug.com/1042453 [ Win ] external/wpt/css/filter-effects/idlharness.any.html [ Timeout Pass ]
 crbug.com/1042453 [ Mac ] external/wpt/css/filter-effects/idlharness.any.html [ Timeout Pass ]
+crbug.com/1042453 [ Win ] external/wpt/css/filter-effects/idlharness.any.worker.html [ Timeout Pass ]
+crbug.com/1042453 [ Mac ] external/wpt/css/filter-effects/idlharness.any.worker.html [ Timeout Pass ]
 
 crbug.com/1042783 external/wpt/css/css-backgrounds/background-size/background-size-near-zero-png.html [ Failure ]
 crbug.com/1042783 external/wpt/css/css-backgrounds/background-size/background-size-near-zero-svg.html [ Failure ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json
index 4d914979..b1ced03 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_7.json
@@ -37,6 +37,12 @@
      {}
     ]
    ],
+   "css/css-flexbox/zero-content-size-with-scrollbar-crash.html": [
+    [
+     "css/css-flexbox/zero-content-size-with-scrollbar-crash.html",
+     {}
+    ]
+   ],
    "css/css-grid/subgrid/contain-strict-nested-subgrid-crash.html": [
     [
      "css/css-grid/subgrid/contain-strict-nested-subgrid-crash.html",
@@ -158896,6 +158902,9 @@
    "fetch/api/policies/referrer-no-referrer.js.headers": [
     []
    ],
+   "fetch/api/policies/referrer-origin-when-cross-origin-service-worker.https-expected.txt": [
+    []
+   ],
    "fetch/api/policies/referrer-origin-when-cross-origin.html.headers": [
     []
    ],
@@ -347606,7 +347615,7 @@
    "support"
   ],
   "README.md": [
-   "3b580da869015b968668bec6a26f3137f4a020a0",
+   "482da428db4ab90a006754ccc40209e9f2f13b7d",
    "support"
   ],
   "WebCryptoAPI/META.yml": [
@@ -383389,6 +383398,10 @@
    "bec931a4e331192704701d261807e9b0ce7d3c6b",
    "reftest"
   ],
+  "css/css-flexbox/zero-content-size-with-scrollbar-crash.html": [
+   "c38659a9d8cff6d0003793896dc83cc78e7a22c4",
+   "crashtest"
+  ],
   "css/css-font-loading/META.yml": [
    "3ac9b655b0606783334ff91f9fba852df8efdbc1",
    "support"
@@ -452145,6 +452158,10 @@
    "4018b837816e669e2819e7731e46a2bdcf141732",
    "testharness"
   ],
+  "fetch/api/policies/referrer-origin-when-cross-origin-service-worker.https-expected.txt": [
+   "5826fb328be576189a361a092663a7cfc681c921",
+   "support"
+  ],
   "fetch/api/policies/referrer-origin-when-cross-origin-service-worker.https.html": [
    "d87192e227119a5a139beedf65bffb5c91a64f79",
    "testharness"
@@ -452154,7 +452171,7 @@
    "testharness"
   ],
   "fetch/api/policies/referrer-origin-when-cross-origin.html": [
-   "18de7364634d18a79861309172ec75ee83676208",
+   "5cd79e4b53615995cb79ad8ad06d9b405151be71",
    "testharness"
   ],
   "fetch/api/policies/referrer-origin-when-cross-origin.html.headers": [
@@ -452162,7 +452179,7 @@
    "support"
   ],
   "fetch/api/policies/referrer-origin-when-cross-origin.js": [
-   "7cd4113f506f26c91275eb65361fc4887e9d1398",
+   "0adadbc55081f0dbb9250be1cec89c7134603bb3",
    "support"
   ],
   "fetch/api/policies/referrer-origin-when-cross-origin.js.headers": [
@@ -458266,7 +458283,7 @@
    "support"
   ],
   "html/cross-origin-opener-policy/blob-popup.https.html": [
-   "4aef1b848917c1f2901eb696a39d5d7f1369a063",
+   "a4e53e7806267049b9190019e2061fd77ac3073a",
    "testharness"
   ],
   "html/cross-origin-opener-policy/blob-popup.https.html.headers": [
@@ -458286,7 +458303,7 @@
    "support"
   ],
   "html/cross-origin-opener-policy/coep-navigate-popup.https.html": [
-   "391929e75cf93c7d9dee24141398c6d6f80135be",
+   "714a4b6c4270900282328af1aacadc8592a0b44e",
    "testharness"
   ],
   "html/cross-origin-opener-policy/coep-navigate-popup.https.html.headers": [
@@ -458302,15 +458319,15 @@
    "support"
   ],
   "html/cross-origin-opener-policy/coep-navigate-popup.https_4-last-expected.txt": [
-   "1e74c90db47ce01fbbe413e8b758d15a021cd3f9",
+   "c323a77a1e49594ddbf3445592f3d16b190fa1d1",
    "support"
   ],
   "html/cross-origin-opener-policy/coep-redirect.https-expected.txt": [
-   "fd033fd632fe81a9f8adf6c93468f21bc8e1ea9b",
+   "7fd7dc9b2cdbcbf65ae28a1fdaf5aa6cfcbaaf98",
    "support"
   ],
   "html/cross-origin-opener-policy/coep-redirect.https.html": [
-   "2c41a92e12f9c77bb4268bbf39c38ff5d7c87fd7",
+   "83f8f8a33d4b2c9c7f23c02011bcc568836e62ea",
    "testharness"
   ],
   "html/cross-origin-opener-policy/coep-redirect.https.html.headers": [
@@ -458318,11 +458335,11 @@
    "support"
   ],
   "html/cross-origin-opener-policy/coep.https-expected.txt": [
-   "4409826428c16d7a8ffb4f670fe3177f51432310",
+   "2b4a10cb374a5cef3975f0be501c0e8b677ff520",
    "support"
   ],
   "html/cross-origin-opener-policy/coep.https.html": [
-   "e909f6275faac90e279a32f68bad34afca27af21",
+   "f6d975564f4fd0a5d272ea6977b7aa93c64e4794",
    "testharness"
   ],
   "html/cross-origin-opener-policy/coep.https.html.headers": [
@@ -458338,11 +458355,11 @@
    "testharness"
   ],
   "html/cross-origin-opener-policy/coop-navigated-popup.https-expected.txt": [
-   "66b2fb564b7063988271105b3d50aa73b8e5e0ff",
+   "5540bd3e8165ca13fd265edc215e864444c24d9d",
    "support"
   ],
   "html/cross-origin-opener-policy/coop-navigated-popup.https.html": [
-   "3c6019ace0b308562cca08d6d6bfd6484882e1db",
+   "e1741932919a426429083544ce44e2f4438cab3d",
    "testharness"
   ],
   "html/cross-origin-opener-policy/coop-navigated-popup.https.html.headers": [
@@ -458506,11 +458523,11 @@
    "support"
   ],
   "html/cross-origin-opener-policy/iframe-popup-same-origin-to-same-origin.https-expected.txt": [
-   "a0c0e0c6d0803474302667292771736e95f106c2",
+   "09d81b126a031dd332726d6466c5383483c0a04f",
    "support"
   ],
   "html/cross-origin-opener-policy/iframe-popup-same-origin-to-same-origin.https.html": [
-   "4c70b1102fd5329c64835203d70a2b5611c54111",
+   "635f7ab3b872c49c436a5cfcb387e63100322ea3",
    "testharness"
   ],
   "html/cross-origin-opener-policy/iframe-popup-same-origin-to-same-origin.https.html.headers": [
@@ -458570,7 +458587,7 @@
    "support"
   ],
   "html/cross-origin-opener-policy/popup-redirect-cache.https.html": [
-   "f05eb492c03234fd5b7620d042bbff0b5b4afda4",
+   "d68c80664bc549ca0e9786653bc0b3759ca31953",
    "testharness"
   ],
   "html/cross-origin-opener-policy/popup-redirect-cache.https.html.headers": [
@@ -458730,11 +458747,11 @@
    "support"
   ],
   "html/cross-origin-opener-policy/resources/common.js": [
-   "59ba33d65b04e26c1db810783b7fdcc96dee8954",
+   "760db60365fbe79a70d37c770a48a162c5058002",
    "support"
   ],
   "html/cross-origin-opener-policy/resources/coop-coep.py": [
-   "e6f655ab728107e4bac31cd7748711f719b01bd3",
+   "0271d7834af98a1d25fd2869c11c6f56b08bfcd3",
    "support"
   ],
   "html/cross-origin-opener-policy/resources/iframe-popup.sub.html": [
@@ -458742,7 +458759,7 @@
    "support"
   ],
   "html/cross-origin-opener-policy/resources/postback.html": [
-   "cf3c93bbe1d3589e9a649db34995e02e2ac9c1e4",
+   "5955e2d7593a51fa112fe82bb97b79add54f3ba0",
    "support"
   ],
   "html/cross-origin-opener-policy/resources/postback.html.headers": [
@@ -467942,7 +467959,7 @@
    "testharness"
   ],
   "html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html": [
-   "6695138c57b6556d29fc6070efa5f1542f9fa3c1",
+   "70c5f194ff63bedea313fe924f8c2f80849d9bb5",
    "testharness"
   ],
   "html/semantics/embedded-content/the-canvas-element/security.pattern.image.fillStyle.cross.html": [
@@ -522002,7 +522019,7 @@
    "support"
   ],
   "tools/wptrunner/wptrunner/executors/executorselenium.py": [
-   "ceca81211e1140577cc3a5f163ffe17c73dd56a3",
+   "39d723a788662dd55c2707eb8d670dba6237cd3c",
    "support"
   ],
   "tools/wptrunner/wptrunner/executors/executorservo.py": [
@@ -522014,7 +522031,7 @@
    "support"
   ],
   "tools/wptrunner/wptrunner/executors/executorwebdriver.py": [
-   "0b329210fc546f9ee50a8a4d0ae02133e3446106",
+   "d09eb1e145170243dc9e74aa68f53d05154283fa",
    "support"
   ],
   "tools/wptrunner/wptrunner/executors/executorwebkit.py": [
@@ -522186,7 +522203,7 @@
    "support"
   ],
   "tools/wptrunner/wptrunner/wptcommandline.py": [
-   "91f1161b01b99f31ef1d3dde05333627bf4365b2",
+   "5b7278b99ff4bfe03981f87671a240141bd0a037",
    "support"
   ],
   "tools/wptrunner/wptrunner/wptlogging.py": [
diff --git a/third_party/blink/web_tests/external/wpt/README.md b/third_party/blink/web_tests/external/wpt/README.md
index 3b580da..482da42 100644
--- a/third_party/blink/web_tests/external/wpt/README.md
+++ b/third_party/blink/web_tests/external/wpt/README.md
@@ -3,16 +3,15 @@
 
 [![Taskcluster CI Status](https://community-tc.services.mozilla.com/api/github/v1/repository/web-platform-tests/wpt/master/badge.svg)](https://community-tc.services.mozilla.com/api/github/v1/repository/web-platform-tests/wpt/master/latest)
 
-The web-platform-tests Project is a W3C-coordinated attempt to build a
-cross-browser test suite for the Web-platform stack. Writing tests in a way
-that allows them to be run in all browsers gives browser projects
-confidence that they are shipping software that is compatible with other
-implementations, and that later implementations will be compatible with
-their implementations. This in turn gives Web authors/developers
-confidence that they can actually rely on the Web platform to deliver on
-the promise of working across browsers and devices without needing extra
-layers of abstraction to paper over the gaps left by specification
-editors and implementors.
+The web-platform-tests Project is a cross-browser test suite for the
+Web-platform stack. Writing tests in a way that allows them to be run in all
+browsers gives browser projects confidence that they are shipping software that
+is compatible with other implementations, and that later implementations will
+be compatible with their implementations. This in turn gives Web
+authors/developers confidence that they can actually rely on the Web platform
+to deliver on the promise of working across browsers and devices without
+needing extra layers of abstraction to paper over the gaps left by
+specification editors and implementors.
 
 The most important sources of information and activity are:
 
diff --git a/third_party/blink/web_tests/external/wpt/css/compositing/root-element-background-transparency-ref.html b/third_party/blink/web_tests/external/wpt/css/compositing/root-element-background-transparency-ref.html
deleted file mode 100644
index 4671d44..0000000
--- a/third_party/blink/web_tests/external/wpt/css/compositing/root-element-background-transparency-ref.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<!doctype HTML>
-<title>Backround color transparency on the root element blends with a white backdrop</title>
-<link rel="author" title="Chris Harrelson" href="mailto:chrishtr@chromium.org">
-<link rel="help" href="https://drafts.fxtf.org/compositing/#pagebackdrop">
-<html style="background: rgb(150, 150, 150)">
-  <div id=spacer style="width: 100px; height: 3000px"></div>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/compositing/root-element-background-transparency.html b/third_party/blink/web_tests/external/wpt/css/compositing/root-element-background-transparency.html
deleted file mode 100644
index 910eb08..0000000
--- a/third_party/blink/web_tests/external/wpt/css/compositing/root-element-background-transparency.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<!doctype HTML>
-<title>Backround color transparency on the root element blends with a white backdrop</title>
-<link rel="author" title="Chris Harrelson" href="mailto:chrishtr@chromium.org">
-<link rel="help" href="https://drafts.fxtf.org/compositing/#pagebackdrop">
-<link rel="match" href="root-element-background-transparency-ref.html">
-<html style="background: rgba(45, 45, 45, 0.5)">
-  <div id=spacer style="width: 100px; height: 3000px"></div>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/compositing/root-element-blend-mode-ref.html b/third_party/blink/web_tests/external/wpt/css/compositing/root-element-blend-mode-ref.html
deleted file mode 100644
index 14c99f7..0000000
--- a/third_party/blink/web_tests/external/wpt/css/compositing/root-element-blend-mode-ref.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<!doctype HTML>
-<title>Blend-mode on the root stacking context blends with the root element's background.</title>
-<html style="background: #000">
-  <div style="width: 50px; height: 50px; background: #000"></div>
-  <div id=spacer style="width: 100px; height: 3000px"></div>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/compositing/root-element-blend-mode.html b/third_party/blink/web_tests/external/wpt/css/compositing/root-element-blend-mode.html
deleted file mode 100644
index 2c97d8b..0000000
--- a/third_party/blink/web_tests/external/wpt/css/compositing/root-element-blend-mode.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!doctype HTML>
-<title>Blend-mode on the root stacking context blends with the root element's background.</title>
-<link rel="author" title="Chris Harrelson" href="mailto:chrishtr@chromium.org">
-<link rel="help" href="https://drafts.fxtf.org/compositing/#pagebackdrop">
-<link rel="match" href="root-element-blend-mode-ref.html">
-<html style="background: #000;">
-  <div style="width: 50px; height: 50px; background: #E33;  mix-blend-mode: multiply"></div>
-  <div id=spacer style="width: 100px; height: 3000px"></div>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/compositing/root-element-filter-ref.html b/third_party/blink/web_tests/external/wpt/css/compositing/root-element-filter-ref.html
deleted file mode 100644
index 27cfb11b..0000000
--- a/third_party/blink/web_tests/external/wpt/css/compositing/root-element-filter-ref.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<!doctype HTML>
-<title>A filter on the root element applies to its background</title>
-<link rel="author" title="Chris Harrelson" href="mailto:chrishtr@chromium.org">
-<link rel="help" href="https://drafts.fxtf.org/compositing/#pagebackdrop">
-<html style="background: #FFF">
-  <div style="width: 50px; height: 50px; background: #1CC"></div>
-  <div id=spacer style="width: 100px; height: 3000px"></div>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/compositing/root-element-filter.html b/third_party/blink/web_tests/external/wpt/css/compositing/root-element-filter.html
deleted file mode 100644
index 62bde9df..0000000
--- a/third_party/blink/web_tests/external/wpt/css/compositing/root-element-filter.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<!doctype HTML>
-<title>A filter on the root element applies to its background</title>
-<link rel="author" title="Chris Harrelson" href="mailto:chrishtr@chromium.org">
-<link rel="help" href="https://drafts.fxtf.org/compositing/#pagebackdrop">
-<link rel="match" href="root-element-filter-ref.html">
-<html style="filter: invert(1); background: #000">
-  <div style="width: 50px; height: 50px; background: #E33"></div>
-  <div id=spacer style="width: 100px; height: 3000px"></div>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/compositing/root-element-opacity-ref.html b/third_party/blink/web_tests/external/wpt/css/compositing/root-element-opacity-ref.html
deleted file mode 100644
index be2348a..0000000
--- a/third_party/blink/web_tests/external/wpt/css/compositing/root-element-opacity-ref.html
+++ /dev/null
@@ -1,7 +0,0 @@
-<!doctype HTML>
-<title>Opacity on the root element blends with a white backdrop</title>
-<link rel="author" title="Chris Harrelson" href="mailto:chrishtr@chromium.org">
-<link rel="help" href="https://drafts.fxtf.org/compositing/#pagebackdrop">
-<html style="background: #DDD">
-  <div id=spacer style="width: 100px; height: 3000px"></div>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/compositing/root-element-opacity.html b/third_party/blink/web_tests/external/wpt/css/compositing/root-element-opacity.html
deleted file mode 100644
index 4885d805..0000000
--- a/third_party/blink/web_tests/external/wpt/css/compositing/root-element-opacity.html
+++ /dev/null
@@ -1,8 +0,0 @@
-<!doctype HTML>
-<title>Opacity on the root element blends with a white background</title>
-<link rel="author" title="Chris Harrelson" href="mailto:chrishtr@chromium.org">
-<link rel="help" href="https://drafts.fxtf.org/compositing/#pagebackdrop">
-<link rel="match" href="root-element-opacity-ref.html">
-<html style="background: #BBB; opacity: 0.5">
-  <div id=spacer style="width: 100px; height: 3000px"></div>
-</html>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/policies/referrer-origin-when-cross-origin-service-worker.https-expected.txt b/third_party/blink/web_tests/external/wpt/fetch/api/policies/referrer-origin-when-cross-origin-service-worker.https-expected.txt
new file mode 100644
index 0000000..5826fb3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/policies/referrer-origin-when-cross-origin-service-worker.https-expected.txt
@@ -0,0 +1,5 @@
+This is a testharness.js-based test.
+PASS Fetch in service worker: referrer with origin-when-cross-origin policy
+FAIL Request's referrer is origin promise_test: Unhandled rejection with value: object "TypeError: Failed to fetch"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/policies/referrer-origin-when-cross-origin.html b/third_party/blink/web_tests/external/wpt/fetch/api/policies/referrer-origin-when-cross-origin.html
index 18de736..5cd79e4b 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/policies/referrer-origin-when-cross-origin.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/policies/referrer-origin-when-cross-origin.html
@@ -7,6 +7,7 @@
     <meta name="help" href="https://fetch.spec.whatwg.org/#http-network-or-cache-fetch">
     <script src="/resources/testharness.js"></script>
     <script src="/resources/testharnessreport.js"></script>
+    <script src="/common/get-host-info.sub.js"></script>
   </head>
   <body>
     <script src="../resources/utils.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/api/policies/referrer-origin-when-cross-origin.js b/third_party/blink/web_tests/external/wpt/fetch/api/policies/referrer-origin-when-cross-origin.js
index 7cd4113f..0adadbc5 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/api/policies/referrer-origin-when-cross-origin.js
+++ b/third_party/blink/web_tests/external/wpt/fetch/api/policies/referrer-origin-when-cross-origin.js
@@ -1,6 +1,7 @@
 if (this.document === undefined) {
   importScripts("/resources/testharness.js");
   importScripts("../resources/utils.js");
+  importScripts("/common/get-host-info.sub.js");
 
   // A nested importScripts() with a referrer-policy should have no effect
   // on overall worker policy.
@@ -8,7 +9,7 @@
 }
 
 var referrerOrigin = location.origin + '/';
-var fetchedUrl = "https://{{domains[www]}}:{{ports[https][0]}}" + dirname(location.pathname) + RESOURCES_DIR + "inspect-headers.py?cors&headers=referer";
+var fetchedUrl = get_host_info().HTTP_REMOTE_ORIGIN + dirname(location.pathname) + RESOURCES_DIR + "inspect-headers.py?cors&headers=referer";
 
 promise_test(function(test) {
   return fetch(fetchedUrl).then(function(resp) {
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/blob-popup.https.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/blob-popup.https.html
index 4aef1b8..a4e53e7 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/blob-popup.https.html
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/blob-popup.https.html
@@ -20,15 +20,17 @@
   const blobContents = `<script>
 const w = window.open("${get_host_info().HTTPS_REMOTE_ORIGIN}/html/cross-origin-opener-policy/resources/coop-coep.py?coop=x&coep=x&channel=${bc.name}", "${bc.name}");
 window.opener.furtherPopup = w;
-
-// w will be closed by its postback iframe. When out of process,
-// window.close() does not work.
-window.opener.test.add_cleanup(() => w.close());
 <\/script>`;
   const blob = new Blob([blobContents], { type: "text/html" });
   const blobURL = URL.createObjectURL(blob);
   const popup = window.open(blobURL);
-  t.add_cleanup(() => popup.close());
+  t.add_cleanup(() => {
+    // Close the popups once the test is complete.
+    // The browsing context of the second popup is closed hence use the
+    //  broadcast channel to trigger the closure.
+    bc.postMessage("close");
+    popup.close();
+  });
   popup.onload = t.step_func(() => {
     assert_equals(popup.opener, window);
     assert_equals(popup.location.href, blobURL);
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep-navigate-popup.https.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep-navigate-popup.https.html
index 391929e7..714a4b6 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep-navigate-popup.https.html
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep-navigate-popup.https.html
@@ -39,7 +39,7 @@
     "title": "coop unsafe-none/coep",
     "coop": "unsafe-none",
     "coep": "require-corp",
-    "opener": true
+    "opener": false
   },
   {
     "title": "coop unsafe-none/no coep",
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep-navigate-popup.https_4-last-expected.txt b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep-navigate-popup.https_4-last-expected.txt
index 1e74c90..c323a77a 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep-navigate-popup.https_4-last-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep-navigate-popup.https_4-last-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-PASS Popup navigating to same-origin with coop unsafe-none/coep
+FAIL Popup navigating to same-origin with coop unsafe-none/coep assert_equals: name expected "" but got "Popup-navigating-to-same-origin-with-coop-unsafe-none/coep"
 FAIL Popup navigating to same-site with coop unsafe-none/coep assert_equals: name expected "" but got "Popup-navigating-to-same-site-with-coop-unsafe-none/coep"
 FAIL Popup navigating to same-origin with coop unsafe-none/no coep assert_equals: name expected "" but got "Popup-navigating-to-same-origin-with-coop-unsafe-none/no-coep"
 FAIL Popup navigating to same-site with coop unsafe-none/no coep assert_equals: name expected "" but got "Popup-navigating-to-same-site-with-coop-unsafe-none/no-coep"
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep-redirect.https-expected.txt b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep-redirect.https-expected.txt
index fd033fd..7fd7dc9 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep-redirect.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep-redirect.https-expected.txt
@@ -3,7 +3,7 @@
 FAIL Redirect from coop/coep to no coop/coep assert_equals: name expected "" but got "Redirect-from-coop/coep-to-no-coop/coep"
 FAIL Redirect from no coop/no coep to coop/coep assert_equals: name expected "" but got "Redirect-from-no-coop/no-coep-to-coop/coep"
 FAIL Redirect from coop/no coep to coop/coep assert_equals: name expected "" but got "Redirect-from-coop/no-coep-to-coop/coep"
-PASS Redirect from coop unsafe-none/coep to coop/coep
-PASS Redirect from coop unsafe-none/coep to coop unsafe-inherit/coep
+FAIL Redirect from coop unsafe-none/coep to coop/coep assert_equals: name expected "" but got "Redirect-from-coop-unsafe-none/coep-to-coop/coep"
+FAIL Redirect from coop unsafe-none/coep to coop unsafe-inherit/coep assert_equals: name expected "" but got "Redirect-from-coop-unsafe-none/coep-to-coop-unsafe-inherit/coep"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep-redirect.https.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep-redirect.https.html
index 2c41a92..83f8f8a 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep-redirect.https.html
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep-redirect.https.html
@@ -47,7 +47,7 @@
     "redirectCOEP": "require-corp",
     "coop": "same-origin",
     "coep": "require-corp",
-    "opener": true
+    "opener": false
   },
   {
     "title": "coop unsafe-none/coep to coop unsafe-inherit/coep",
@@ -55,7 +55,7 @@
     "redirectCOEP": "require-corp",
     "coop": "unsafe-none",
     "coep": "require-corp",
-    "opener": true
+    "opener": false
   }
 ].forEach(variant => {
   const title = `Redirect from ${variant.title}`;
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep.https-expected.txt b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep.https-expected.txt
index 4409826..2b4a10c 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep.https-expected.txt
@@ -1,7 +1,7 @@
 This is a testharness.js-based test.
 PASS Same-origin popup with coop/coep
 FAIL historical: "same-site" popup with coop/coep assert_equals: name expected "" but got "same-site-popup-with-coop/coep"
-PASS Same-origin popup with coop unsafe-none/coep
+FAIL Same-origin popup with coop unsafe-none/coep assert_equals: name expected "" but got "popup-with-coop-unsafe-none/coep"
 FAIL historical: "same-site" popup with coop unsafe-none/coep assert_equals: name expected "" but got "same-site-popup-with-coop-unsafe-none/coep"
 FAIL Same-origin popup with coop unsafe-none without coep assert_equals: name expected "" but got "popup-with-coop-unsafe-none-without-coep"
 FAIL historical: "same-site" popup with coop unsafe-none without coep assert_equals: name expected "" but got "same-site-popup-with-coop-unsafe-none-without-coep"
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep.https.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep.https.html
index e909f62..f6d9755 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep.https.html
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coep.https.html
@@ -17,7 +17,7 @@
     "title": "popup with coop unsafe-none/coep",
     "coop": "unsafe-none",
     "coep": "require-corp",
-    "opener": true
+    "opener": false
   },
   {
     "title": "popup with coop unsafe-none without coep",
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coop-navigated-popup.https-expected.txt b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coop-navigated-popup.https-expected.txt
index 66b2fb5..5540bd3 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coop-navigated-popup.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coop-navigated-popup.https-expected.txt
@@ -1,4 +1,5 @@
 This is a testharness.js-based test.
+Harness Error. harness_status.status = 1 , harness_status.message = Test named 'Open a popup to a document without COOP, then navigate it to a document with' specified 1 'cleanup' function, and 1 failed.
 FAIL Open a popup to a document without COOP, then navigate it to a document with assert_equals: expected 0 but got 36
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coop-navigated-popup.https.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coop-navigated-popup.https.html
index 3c6019a..e174193 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coop-navigated-popup.https.html
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/coop-navigated-popup.https.html
@@ -12,7 +12,12 @@
   const noCOOP = "/common/blank.html";
   const popupName = token();
   const popup = window.open(noCOOP, popupName);
-  t.add_cleanup(() => popup.close());
+  // Close the popup once the test is complete.
+  // The browsing context is closed after the navigation hence use the broadcast channel
+  // to trigger the closure.
+  t.add_cleanup(() => {
+    bc.postMessage("close");
+  });
   popup.onload = t.step_func(() => {
     assert_equals(popup.name, popupName);
     assert_equals(new URL(popup.document.URL).pathname, noCOOP);
@@ -23,6 +28,7 @@
       // string comparison to "" to keep the random token out of error messages.
       assert_equals(payload.name.length, 0);
       assert_false(payload.opener);
+      assert_true(popup.closed);
     });
     const coop = `resources/coop-coep.py?coop=same-origin&coep=&channel=${channel.name}`;
     popup.location = coop;
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/iframe-popup-same-origin-to-same-origin.https-expected.txt b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/iframe-popup-same-origin-to-same-origin.https-expected.txt
index a0c0e0c..09d81b1 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/iframe-popup-same-origin-to-same-origin.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/iframe-popup-same-origin-to-same-origin.https-expected.txt
@@ -1,12 +1,12 @@
 This is a testharness.js-based test.
 PASS same-origin with SAME_ORIGIN iframe opening popup a SAME_ORIGIN with COOP: same-origin
-PASS same-origin with SAME_SITE iframe opening popup a SAME_ORIGIN with COOP: same-origin
-PASS same-origin with CROSS_ORIGIN iframe opening popup a SAME_ORIGIN with COOP: same-origin
+FAIL same-origin with SAME_SITE iframe opening popup a SAME_ORIGIN with COOP: same-origin assert_equals: name expected "" but got "SAME_SITE_iframe_opening_SAME_ORIGIN_popup_with_coop_same-origin"
+FAIL same-origin with CROSS_ORIGIN iframe opening popup a SAME_ORIGIN with COOP: same-origin assert_equals: name expected "" but got "CROSS_ORIGIN_iframe_opening_SAME_ORIGIN_popup_with_coop_same-origin"
 FAIL same-origin with SAME_ORIGIN iframe opening popup a SAME_SITE with COOP: same-origin assert_equals: opener expected false but got true
-PASS same-origin with SAME_SITE iframe opening popup a SAME_SITE with COOP: same-origin
-PASS same-origin with CROSS_ORIGIN iframe opening popup a SAME_SITE with COOP: same-origin
+FAIL same-origin with SAME_SITE iframe opening popup a SAME_SITE with COOP: same-origin assert_equals: name expected "" but got "SAME_SITE_iframe_opening_SAME_SITE_popup_with_coop_same-origin"
+FAIL same-origin with CROSS_ORIGIN iframe opening popup a SAME_SITE with COOP: same-origin assert_equals: name expected "" but got "CROSS_ORIGIN_iframe_opening_SAME_SITE_popup_with_coop_same-origin"
 FAIL same-origin with SAME_ORIGIN iframe opening popup a CROSS_ORIGIN with COOP: same-origin assert_equals: opener expected false but got true
-PASS same-origin with SAME_SITE iframe opening popup a CROSS_ORIGIN with COOP: same-origin
-PASS same-origin with CROSS_ORIGIN iframe opening popup a CROSS_ORIGIN with COOP: same-origin
+FAIL same-origin with SAME_SITE iframe opening popup a CROSS_ORIGIN with COOP: same-origin assert_equals: name expected "" but got "SAME_SITE_iframe_opening_CROSS_ORIGIN_popup_with_coop_same-origin"
+FAIL same-origin with CROSS_ORIGIN iframe opening popup a CROSS_ORIGIN with COOP: same-origin assert_equals: name expected "" but got "CROSS_ORIGIN_iframe_opening_CROSS_ORIGIN_popup_with_coop_same-origin"
 Harness: the test ran to completion.
 
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/iframe-popup-same-origin-to-same-origin.https.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/iframe-popup-same-origin-to-same-origin.https.html
index 4c70b110..635f7ab 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/iframe-popup-same-origin-to-same-origin.https.html
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/iframe-popup-same-origin-to-same-origin.https.html
@@ -10,14 +10,14 @@
 <script>
 [
 [SAME_ORIGIN, SAME_ORIGIN, "same-origin", true, true],
-[SAME_SITE, SAME_ORIGIN, "same-origin", false, true],
-[CROSS_ORIGIN, SAME_ORIGIN, "same-origin", false, true],
+[SAME_SITE, SAME_ORIGIN, "same-origin", false, false],
+[CROSS_ORIGIN, SAME_ORIGIN, "same-origin", false, false],
 [SAME_ORIGIN, SAME_SITE, "same-origin", false, false],
-[SAME_SITE, SAME_SITE, "same-origin", false, true],
-[CROSS_ORIGIN, SAME_SITE, "same-origin", false, true],
+[SAME_SITE, SAME_SITE, "same-origin", false, false],
+[CROSS_ORIGIN, SAME_SITE, "same-origin", false, false],
 [SAME_ORIGIN, CROSS_ORIGIN, "same-origin", false, false],
-[SAME_SITE, CROSS_ORIGIN, "same-origin", false, true],
-[CROSS_ORIGIN, CROSS_ORIGIN, "same-origin", false, true],
+[SAME_SITE, CROSS_ORIGIN, "same-origin", false, false],
+[CROSS_ORIGIN, CROSS_ORIGIN, "same-origin", false, false],
 ].forEach( value => {
     run_coop_test_iframe("same-origin", value[0], value[1], value[2], value[3], value[4]);
 });
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-redirect-cache.https.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-redirect-cache.https.html
index f05eb49..d68c806 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-redirect-cache.https.html
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/popup-redirect-cache.https.html
@@ -15,6 +15,7 @@
     const payload = event.data;
     assert_equals(payload.name, hasOpener ? channelName : "");
     assert_equals(payload.opener, hasOpener);
+    assert_equals(w.closed, !hasOpener);
     bc.close()
 
     // test the same url for cache
@@ -23,9 +24,7 @@
 
   const w = window.open(url, channelName);
 
-  // w will be closed by its postback iframe. When out of process,
-  // window.close() does not work.
-  t.add_cleanup(() => w.close());
+  // The popup is closed by url_test.
 }
 
 // Redirect from hostA to hostB with same coop and coep.
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/common.js b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/common.js
index 59ba33d6..760db60 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/common.js
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/common.js
@@ -12,13 +12,17 @@
     if (openerDOMAccess !== undefined) {
       assert_equals(payload.openerDOMAccess, openerDOMAccess, 'openerDOMAccess');
     }
+    assert_equals(w.closed, !hasOpener, 'Openee browsing context closed');
   });
 
   const w = window.open(url, channelName);
 
-  // w will be closed by its postback iframe. When out of process,
-  // window.close() does not work.
-  t.add_cleanup(() => w.close());
+  // Close the popup once the test is complete.
+  // The browsing context might be closed hence use the broadcast channel
+  // to trigger the closure.
+  t.add_cleanup(() => {
+    bc.postMessage("close");
+  });
 }
 
 function coop_coep_test(t, host, coop, coep, channelName, hasOpener, openerDOMAccess) {
@@ -43,7 +47,14 @@
   const name = iframe_origin.name + "_iframe_opening_" + popup_origin.name + "_popup_with_coop_" + popup_coop;
   async_test(t => {
       const frame = document.createElement("iframe");
-      t.add_cleanup(() => { frame.remove(); });
+
+      // Close the popup and remove the frame once the test is
+      // complete. The browsing context might be closed hence use the
+      // broadcast channel to trigger the closure.
+      t.add_cleanup(() => {
+        frame.remove();
+        bc.postMessage("close");
+      });
 
       const origin = CROSS_ORIGIN.origin;
       const path = new URL("resources/iframe-popup.sub.html", window.location).pathname;
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/coop-coep.py b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/coop-coep.py
index e6f655ab..0271d78 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/coop-coep.py
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/coop-coep.py
@@ -50,6 +50,13 @@
       openerDOMAccessAllowed = !!self.opener.document.URL;
     } catch(ex) {
     }
+    // Handle the response from the frame, closing the popup once the
+    // test completes.
+    addEventListener("message", event => {
+      if (event.data == "close") {
+        close();
+      }
+    });
     const iframe = document.querySelector("iframe");
     iframe.onload = () => {
       const payload = { name: self.name, opener: !!self.opener, openerDOMAccess: openerDOMAccessAllowed };
diff --git a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/postback.html b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/postback.html
index cf3c93b..5955e2d 100644
--- a/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/postback.html
+++ b/third_party/blink/web_tests/external/wpt/html/cross-origin-opener-policy/resources/postback.html
@@ -3,8 +3,17 @@
 <script>
 const channelName = new URL(location).searchParams.get("channel");
 const bc = new BroadcastChannel(channelName);
+
+// Handle the close message from the test-cleanup, forwarding it to the
+// top level document, as this iframe and the opening document might not
+// be able to close the popup.
+bc.onmessage = event => {
+  if (event.data == "close") {
+    top.postMessage("close", "*");
+  }
+};
+
 window.addEventListener("message", event => {
   bc.postMessage(event.data);
-  window.parent.close();
 });
 </script>
diff --git a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html
index 6695138c..70c5f19 100644
--- a/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html
+++ b/third_party/blink/web_tests/external/wpt/html/semantics/embedded-content/the-canvas-element/security.pattern.fillStyle.sub.html
@@ -3,6 +3,7 @@
 <title>Canvas test: security.pattern.canvas.fillStyle.cross</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/media.js"></script>
 <script src="/2dcontext/resources/canvas-tests.js"></script>
 
@@ -11,8 +12,8 @@
 
 <script>
 
-forEachCanvasSource("http://{{domains[www1]}}:{{ports[http][0]}}",
-                    "http://{{domains[]}}:{{ports[http][0]}}",
+forEachCanvasSource(get_host_info().HTTP_REMOTE_ORIGIN,
+                    get_host_info().HTTP_ORIGIN,
                     (name, factory) => {
   promise_test(_ => {
     return factory().then(source => {
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorselenium.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorselenium.py
index ceca8121..39d723a 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorselenium.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorselenium.py
@@ -1,11 +1,12 @@
+from __future__ import absolute_import
 import json
 import os
 import socket
 import threading
 import time
 import traceback
-import urlparse
 import uuid
+from six.moves.urllib.parse import urljoin
 
 from .base import (CallbackHandler,
                    RefTestExecutor,
@@ -87,8 +88,8 @@
     def load_runner(self, url_protocol):
         if self.runner_handle:
             self.webdriver.switch_to_window(self.runner_handle)
-        url = urlparse.urljoin(self.parent.executor.server_url(url_protocol),
-                               "/testharness_runner.html")
+        url = urljoin(self.parent.executor.server_url(url_protocol),
+                      "/testharness_runner.html")
         self.logger.debug("Loading %s" % url)
         self.webdriver.get(url)
         self.runner_handle = self.webdriver.current_window_handle
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py
index 0b32921..d09eb1e1 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/executors/executorwebdriver.py
@@ -1,11 +1,12 @@
+from __future__ import absolute_import
 import json
 import os
 import socket
 import threading
 import time
 import traceback
-import urlparse
 import uuid
+from six.moves.urllib.parse import urljoin
 
 from .base import (CallbackHandler,
                    CrashtestExecutor,
@@ -86,8 +87,8 @@
     def load_runner(self, url_protocol):
         if self.runner_handle:
             self.webdriver.window_handle = self.runner_handle
-        url = urlparse.urljoin(self.parent.executor.server_url(url_protocol),
-                               "/testharness_runner.html")
+        url = urljoin(self.parent.executor.server_url(url_protocol),
+                      "/testharness_runner.html")
         self.logger.debug("Loading %s" % url)
 
         self.webdriver.url = url
diff --git a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wptcommandline.py b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wptcommandline.py
index 91f1161b..5b7278b 100644
--- a/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wptcommandline.py
+++ b/third_party/blink/web_tests/external/wpt/tools/wptrunner/wptrunner/wptcommandline.py
@@ -1,4 +1,4 @@
-from __future__ import print_function
+from __future__ import absolute_import, print_function
 import argparse
 import os
 import sys
@@ -16,9 +16,9 @@
 
 
 def url_or_path(path):
-    import urlparse
+    from six.moves.urllib.parse import urlparse
 
-    parsed = urlparse.urlparse(path)
+    parsed = urlparse(path)
     if len(parsed.scheme) > 2:
         return path
     else:
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/compositing/lots-of-img-layers-expected.png b/third_party/blink/web_tests/flag-specific/composite-after-paint/compositing/lots-of-img-layers-expected.png
deleted file mode 100644
index 6f9fc57..0000000
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/compositing/lots-of-img-layers-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png b/third_party/blink/web_tests/flag-specific/composite-after-paint/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
deleted file mode 100644
index 0468f555..0000000
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/fast/forms/calendar-picker/calendar-picker-appearance-zoom125-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/forms/checkbox-focus-by-mouse-then-keydown-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/forms/checkbox-focus-by-mouse-then-keydown-expected.txt
index 2c6302f..8be630f 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/forms/checkbox-focus-by-mouse-then-keydown-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/forms/checkbox-focus-by-mouse-then-keydown-expected.txt
@@ -7,8 +7,8 @@
       "backgroundColor": "#FFFFFF",
       "paintInvalidations": [
         {
-          "object": "LayoutBlockFlow INPUT",
-          "rect": [10, 9, 17, 17],
+          "object": "LayoutNGBlockFlow INPUT",
+          "rect": [8, 7, 21, 21],
           "reason": "subtree"
         }
       ]
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/forms/range-focus-by-mouse-then-keydown-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/forms/range-focus-by-mouse-then-keydown-expected.txt
index 7d8a007..5022cf1f 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/forms/range-focus-by-mouse-then-keydown-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/forms/range-focus-by-mouse-then-keydown-expected.txt
@@ -8,7 +8,7 @@
       "paintInvalidations": [
         {
           "object": "LayoutSlider INPUT",
-          "rect": [9, 9, 131, 18],
+          "rect": [8, 8, 133, 20],
           "reason": "subtree"
         },
         {
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
index e4dbf1a..84335d70 100644
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/paint/invalidation/svg/scrolling-embedded-svg-file-image-repaint-problem-expected.txt
@@ -18,7 +18,7 @@
         },
         {
           "object": "NGPhysicalBoxFragment LayoutInline A",
-          "rect": [382, 970, 44, 23],
+          "rect": [380, 968, 48, 27],
           "reason": "appeared"
         },
         {
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/svg/as-background-image/background-image-preserveaspectRatio-support-expected.png b/third_party/blink/web_tests/flag-specific/composite-after-paint/svg/as-background-image/background-image-preserveaspectRatio-support-expected.png
deleted file mode 100644
index 4570a36c..0000000
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/svg/as-background-image/background-image-preserveaspectRatio-support-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
deleted file mode 100644
index f6ef9da..0000000
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/scalefactor150/fast/hidpi/static/calendar-picker-appearance-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance-expected.png b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance-expected.png
deleted file mode 100644
index 88c1c1ca..0000000
--- a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance-expected.png
+++ /dev/null
Binary files differ
diff --git a/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
new file mode 100644
index 0000000..5b79a7f
--- /dev/null
+++ b/third_party/blink/web_tests/flag-specific/composite-after-paint/virtual/scalefactor200withzoom/fast/hidpi/static/validation-bubble-appearance-hidpi-expected.png
Binary files differ
diff --git a/third_party/polymer/v1_0/components-chromium/iron-a11y-announcer/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-a11y-announcer/BUILD.gn
index 149d87b..fb3178f 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-a11y-announcer/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-a11y-announcer/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v1_0/components-chromium/iron-a11y-keys-behavior/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-a11y-keys-behavior/BUILD.gn
index facca4f5..0d01e51 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-a11y-keys-behavior/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-a11y-keys-behavior/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v1_0/components-chromium/iron-a11y-keys/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-a11y-keys/BUILD.gn
index 293bea7..79ed522 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-a11y-keys/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-a11y-keys/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,7 +7,5 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("iron-a11y-keys-extracted") {
-  deps = [
-    "../iron-a11y-keys-behavior:iron-a11y-keys-behavior-extracted",
-  ]
+  deps = [ "../iron-a11y-keys-behavior:iron-a11y-keys-behavior-extracted" ]
 }
diff --git a/third_party/polymer/v1_0/components-chromium/iron-behaviors/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-behaviors/BUILD.gn
index e3dd06a9..3306dd1 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-behaviors/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-behaviors/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v1_0/components-chromium/iron-collapse/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-collapse/BUILD.gn
index 301a4e3..6cf68037 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-collapse/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-collapse/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,7 +7,5 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("iron-collapse-extracted") {
-  deps = [
-    "../iron-resizable-behavior:iron-resizable-behavior-extracted",
-  ]
+  deps = [ "../iron-resizable-behavior:iron-resizable-behavior-extracted" ]
 }
diff --git a/third_party/polymer/v1_0/components-chromium/iron-dropdown/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-dropdown/BUILD.gn
index 1fe9c23..074a228 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-dropdown/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-dropdown/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -16,7 +16,5 @@
 }
 
 js_library("iron-dropdown-scroll-manager-extracted") {
-  deps = [
-    "../iron-overlay-behavior:iron-scroll-manager-extracted",
-  ]
+  deps = [ "../iron-overlay-behavior:iron-scroll-manager-extracted" ]
 }
diff --git a/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/BUILD.gn
index 7410bdc..22f0e261 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-fit-behavior/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v1_0/components-chromium/iron-icon/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-icon/BUILD.gn
index 504bc78..a8c5db3 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-icon/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-icon/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,7 +7,5 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("iron-icon-extracted") {
-  deps = [
-    "../iron-meta:iron-meta-extracted",
-  ]
+  deps = [ "../iron-meta:iron-meta-extracted" ]
 }
diff --git a/third_party/polymer/v1_0/components-chromium/iron-iconset-svg/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-iconset-svg/BUILD.gn
index 4010b38..7102e40 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-iconset-svg/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-iconset-svg/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,7 +7,5 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("iron-iconset-svg-extracted") {
-  deps = [
-    "../iron-meta:iron-meta-extracted",
-  ]
+  deps = [ "../iron-meta:iron-meta-extracted" ]
 }
diff --git a/third_party/polymer/v1_0/components-chromium/iron-input/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-input/BUILD.gn
index c21a07f..8ee4910f 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-input/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-input/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v1_0/components-chromium/iron-list/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-list/BUILD.gn
index 43f8943..7dc5cd7e 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-list/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-list/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v1_0/components-chromium/iron-location/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-location/BUILD.gn
index e502ced..b6d216f2 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-location/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-location/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v1_0/components-chromium/iron-media-query/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-media-query/BUILD.gn
index 05879f1..2e96db5 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-media-query/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-media-query/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v1_0/components-chromium/iron-meta/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-meta/BUILD.gn
index 3b207b2..5458d02 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-meta/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-meta/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/BUILD.gn
index 9305be9..f9ed61f 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-overlay-behavior/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v1_0/components-chromium/iron-pages/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-pages/BUILD.gn
index 430f3615..9e3979d 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-pages/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-pages/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v1_0/components-chromium/iron-range-behavior/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-range-behavior/BUILD.gn
index c906aeb2..6ef24aa7 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-range-behavior/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-range-behavior/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/BUILD.gn
index b04c9fb..81c96523 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/BUILD.gn
index 3b41716..3593f9b 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-scroll-target-behavior/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v1_0/components-chromium/iron-scroll-threshold/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-scroll-threshold/BUILD.gn
index 9b65c19..66b9197 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-scroll-threshold/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-scroll-threshold/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,7 +7,6 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("iron-scroll-threshold-extracted") {
-  deps = [
-    "../iron-scroll-target-behavior:iron-scroll-target-behavior-extracted",
-  ]
+  deps =
+      [ "../iron-scroll-target-behavior:iron-scroll-target-behavior-extracted" ]
 }
diff --git a/third_party/polymer/v1_0/components-chromium/iron-selector/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-selector/BUILD.gn
index 3ae53a1d7..99546aec 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-selector/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-selector/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,22 +7,16 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("iron-multi-selectable-extracted") {
-  deps = [
-    ":iron-selectable-extracted",
-  ]
+  deps = [ ":iron-selectable-extracted" ]
 }
 
 js_library("iron-selectable-extracted") {
-  deps = [
-    ":iron-selection-extracted",
-  ]
+  deps = [ ":iron-selection-extracted" ]
 }
 
 js_library("iron-selection-extracted") {
 }
 
 js_library("iron-selector-extracted") {
-  deps = [
-    ":iron-multi-selectable-extracted",
-  ]
+  deps = [ ":iron-multi-selectable-extracted" ]
 }
diff --git a/third_party/polymer/v1_0/components-chromium/iron-validatable-behavior/BUILD.gn b/third_party/polymer/v1_0/components-chromium/iron-validatable-behavior/BUILD.gn
index cd8d61e..8ca3573 100644
--- a/third_party/polymer/v1_0/components-chromium/iron-validatable-behavior/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/iron-validatable-behavior/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,7 +7,5 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("iron-validatable-behavior-extracted") {
-  deps = [
-    "../iron-meta:iron-meta-extracted",
-  ]
+  deps = [ "../iron-meta:iron-meta-extracted" ]
 }
diff --git a/third_party/polymer/v1_0/components-chromium/neon-animation/BUILD.gn b/third_party/polymer/v1_0/components-chromium/neon-animation/BUILD.gn
index d27d489..96b8ea5 100644
--- a/third_party/polymer/v1_0/components-chromium/neon-animation/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/neon-animation/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -28,7 +28,5 @@
 }
 
 js_library("neon-animation-runner-behavior-extracted") {
-  deps = [
-    ":neon-animatable-behavior-extracted",
-  ]
+  deps = [ ":neon-animatable-behavior-extracted" ]
 }
diff --git a/third_party/polymer/v1_0/components-chromium/neon-animation/animations/BUILD.gn b/third_party/polymer/v1_0/components-chromium/neon-animation/animations/BUILD.gn
index 68a8d82..6dfbe86 100644
--- a/third_party/polymer/v1_0/components-chromium/neon-animation/animations/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/neon-animation/animations/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,13 +7,9 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("fade-in-animation-extracted") {
-  deps = [
-    "..:neon-animation-behavior-extracted",
-  ]
+  deps = [ "..:neon-animation-behavior-extracted" ]
 }
 
 js_library("fade-out-animation-extracted") {
-  deps = [
-    "..:neon-animation-behavior-extracted",
-  ]
+  deps = [ "..:neon-animation-behavior-extracted" ]
 }
diff --git a/third_party/polymer/v1_0/components-chromium/paper-behaviors/BUILD.gn b/third_party/polymer/v1_0/components-chromium/paper-behaviors/BUILD.gn
index ee3258f..e52d3bc 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-behaviors/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/paper-behaviors/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v1_0/components-chromium/paper-input/BUILD.gn b/third_party/polymer/v1_0/components-chromium/paper-input/BUILD.gn
index 4e8f276f..3f679707 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-input/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/paper-input/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -13,7 +13,5 @@
 }
 
 js_library("paper-input-error-extracted") {
-  deps = [
-    ":paper-input-addon-behavior-extracted",
-  ]
+  deps = [ ":paper-input-addon-behavior-extracted" ]
 }
diff --git a/third_party/polymer/v1_0/components-chromium/paper-progress/BUILD.gn b/third_party/polymer/v1_0/components-chromium/paper-progress/BUILD.gn
index d3f60da..f84054a 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-progress/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/paper-progress/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,7 +7,5 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("paper-progress-extracted") {
-  deps = [
-    "../iron-range-behavior:iron-range-behavior-extracted",
-  ]
+  deps = [ "../iron-range-behavior:iron-range-behavior-extracted" ]
 }
diff --git a/third_party/polymer/v1_0/components-chromium/paper-ripple/BUILD.gn b/third_party/polymer/v1_0/components-chromium/paper-ripple/BUILD.gn
index aab1bad..01b5adf9 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-ripple/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/paper-ripple/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,7 +7,5 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("paper-ripple-extracted") {
-  deps = [
-    "../iron-a11y-keys-behavior:iron-a11y-keys-behavior-extracted",
-  ]
+  deps = [ "../iron-a11y-keys-behavior:iron-a11y-keys-behavior-extracted" ]
 }
diff --git a/third_party/polymer/v1_0/components-chromium/paper-spinner/BUILD.gn b/third_party/polymer/v1_0/components-chromium/paper-spinner/BUILD.gn
index 2677d9ac..21e3387 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-spinner/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/paper-spinner/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -10,7 +10,5 @@
 }
 
 js_library("paper-spinner-lite-extracted") {
-  deps = [
-    ":paper-spinner-behavior-extracted",
-  ]
+  deps = [ ":paper-spinner-behavior-extracted" ]
 }
diff --git a/third_party/polymer/v1_0/components-chromium/paper-tooltip/BUILD.gn b/third_party/polymer/v1_0/components-chromium/paper-tooltip/BUILD.gn
index 50e30af1..b2f9403f 100644
--- a/third_party/polymer/v1_0/components-chromium/paper-tooltip/BUILD.gn
+++ b/third_party/polymer/v1_0/components-chromium/paper-tooltip/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v3_0/components-chromium/font-roboto/BUILD.gn b/third_party/polymer/v3_0/components-chromium/font-roboto/BUILD.gn
index e5345d2..f232c75 100644
--- a/third_party/polymer/v3_0/components-chromium/font-roboto/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/font-roboto/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v3_0/components-chromium/iron-a11y-announcer/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-a11y-announcer/BUILD.gn
index 91fc0d46f..c9d5e96f 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-a11y-announcer/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-a11y-announcer/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,7 +7,5 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("iron-a11y-announcer") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
diff --git a/third_party/polymer/v3_0/components-chromium/iron-a11y-keys-behavior/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-a11y-keys-behavior/BUILD.gn
index 953a4cfb..1c269bb 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-a11y-keys-behavior/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-a11y-keys-behavior/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,7 +7,5 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("iron-a11y-keys-behavior") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
diff --git a/third_party/polymer/v3_0/components-chromium/iron-a11y-keys/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-a11y-keys/BUILD.gn
index a95f20a8..a28030e 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-a11y-keys/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-a11y-keys/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v3_0/components-chromium/iron-behaviors/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-behaviors/BUILD.gn
index 9622f7e..71c988e 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-behaviors/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-behaviors/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -15,7 +15,5 @@
 }
 
 js_library("iron-control-state") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
diff --git a/third_party/polymer/v3_0/components-chromium/iron-collapse/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-collapse/BUILD.gn
index 51a622a..7761a4a 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-collapse/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-collapse/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v3_0/components-chromium/iron-dropdown/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-dropdown/BUILD.gn
index 4d12238..aa6826d 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-dropdown/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-dropdown/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -17,7 +17,5 @@
 }
 
 js_library("iron-dropdown-scroll-manager") {
-  deps = [
-    "../iron-overlay-behavior:iron-scroll-manager",
-  ]
+  deps = [ "../iron-overlay-behavior:iron-scroll-manager" ]
 }
diff --git a/third_party/polymer/v3_0/components-chromium/iron-fit-behavior/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-fit-behavior/BUILD.gn
index 49cc0041..29ff79e4 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-fit-behavior/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-fit-behavior/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,7 +7,5 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("iron-fit-behavior") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
diff --git a/third_party/polymer/v3_0/components-chromium/iron-flex-layout/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-flex-layout/BUILD.gn
index 3a0fc2cf..084fad9f 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-flex-layout/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-flex-layout/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,13 +7,9 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("iron-flex-layout") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
 
 js_library("iron-flex-layout-classes") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
diff --git a/third_party/polymer/v3_0/components-chromium/iron-icon/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-icon/BUILD.gn
index 9974bafe..064b4627 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-icon/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-icon/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v3_0/components-chromium/iron-iconset-svg/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-iconset-svg/BUILD.gn
index e7ac6ba08..006b423a 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-iconset-svg/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-iconset-svg/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v3_0/components-chromium/iron-input/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-input/BUILD.gn
index f6a553c..6d1e99e 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-input/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-input/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v3_0/components-chromium/iron-list/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-list/BUILD.gn
index b5f9129..4240557 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-list/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-list/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v3_0/components-chromium/iron-location/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-location/BUILD.gn
index 043c444e..e5ebeff 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-location/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-location/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,13 +7,9 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("iron-location") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
 
 js_library("iron-query-params") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
diff --git a/third_party/polymer/v3_0/components-chromium/iron-media-query/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-media-query/BUILD.gn
index d0a473f..3c23d08 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-media-query/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-media-query/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,7 +7,5 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("iron-media-query") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
diff --git a/third_party/polymer/v3_0/components-chromium/iron-meta/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-meta/BUILD.gn
index dae2816e..a08a6a18 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-meta/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-meta/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,7 +7,5 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("iron-meta") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
diff --git a/third_party/polymer/v3_0/components-chromium/iron-overlay-behavior/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-overlay-behavior/BUILD.gn
index 1d276827..5e0cc87 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-overlay-behavior/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-overlay-behavior/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,15 +7,11 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("iron-focusables-helper") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
 
 js_library("iron-overlay-backdrop") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
 
 js_library("iron-overlay-behavior") {
@@ -38,7 +34,5 @@
 }
 
 js_library("iron-scroll-manager") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
diff --git a/third_party/polymer/v3_0/components-chromium/iron-pages/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-pages/BUILD.gn
index d29f7e9..e801d83 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-pages/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-pages/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v3_0/components-chromium/iron-range-behavior/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-range-behavior/BUILD.gn
index f4822f8..569152cc 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-range-behavior/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-range-behavior/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,7 +7,5 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("iron-range-behavior") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
diff --git a/third_party/polymer/v3_0/components-chromium/iron-resizable-behavior/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-resizable-behavior/BUILD.gn
index 0f96c9d..59cf354 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-resizable-behavior/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-resizable-behavior/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,7 +7,5 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("iron-resizable-behavior") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
diff --git a/third_party/polymer/v3_0/components-chromium/iron-scroll-target-behavior/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-scroll-target-behavior/BUILD.gn
index 26d261a9..664a7ab 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-scroll-target-behavior/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-scroll-target-behavior/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,7 +7,5 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("iron-scroll-target-behavior") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
diff --git a/third_party/polymer/v3_0/components-chromium/iron-scroll-threshold/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-scroll-threshold/BUILD.gn
index d75b199..19acd92 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-scroll-threshold/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-scroll-threshold/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v3_0/components-chromium/iron-selector/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-selector/BUILD.gn
index 9736a67b..656367c 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-selector/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-selector/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -21,9 +21,7 @@
 }
 
 js_library("iron-selection") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
 
 js_library("iron-selector") {
diff --git a/third_party/polymer/v3_0/components-chromium/iron-test-helpers/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-test-helpers/BUILD.gn
index 7c9dd2c..090b65d 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-test-helpers/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-test-helpers/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,7 +7,5 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("mock-interactions") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
diff --git a/third_party/polymer/v3_0/components-chromium/iron-validatable-behavior/BUILD.gn b/third_party/polymer/v3_0/components-chromium/iron-validatable-behavior/BUILD.gn
index fd0d308a..790b7ad 100644
--- a/third_party/polymer/v3_0/components-chromium/iron-validatable-behavior/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/iron-validatable-behavior/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v3_0/components-chromium/neon-animation/BUILD.gn b/third_party/polymer/v3_0/components-chromium/neon-animation/BUILD.gn
index 7a01eaba..b3f1e15 100644
--- a/third_party/polymer/v3_0/components-chromium/neon-animation/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/neon-animation/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -15,9 +15,7 @@
 }
 
 js_library("neon-animatable-behavior") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
 
 js_library("neon-animated-pages") {
@@ -30,9 +28,7 @@
 }
 
 js_library("neon-animation-behavior") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
 
 js_library("neon-animation-runner-behavior") {
diff --git a/third_party/polymer/v3_0/components-chromium/neon-animation/animations/BUILD.gn b/third_party/polymer/v3_0/components-chromium/neon-animation/animations/BUILD.gn
index 0c6a170..73be497 100644
--- a/third_party/polymer/v3_0/components-chromium/neon-animation/animations/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/neon-animation/animations/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v3_0/components-chromium/paper-behaviors/BUILD.gn b/third_party/polymer/v3_0/components-chromium/paper-behaviors/BUILD.gn
index 2665a266..baf0ee53 100644
--- a/third_party/polymer/v3_0/components-chromium/paper-behaviors/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/paper-behaviors/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v3_0/components-chromium/paper-input/BUILD.gn b/third_party/polymer/v3_0/components-chromium/paper-input/BUILD.gn
index 575500af..33b65ee 100644
--- a/third_party/polymer/v3_0/components-chromium/paper-input/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/paper-input/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,9 +7,7 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("paper-input-addon-behavior") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
 
 js_library("paper-input-container") {
diff --git a/third_party/polymer/v3_0/components-chromium/paper-progress/BUILD.gn b/third_party/polymer/v3_0/components-chromium/paper-progress/BUILD.gn
index 1da4c66..c162d3ca 100644
--- a/third_party/polymer/v3_0/components-chromium/paper-progress/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/paper-progress/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v3_0/components-chromium/paper-ripple/BUILD.gn b/third_party/polymer/v3_0/components-chromium/paper-ripple/BUILD.gn
index 79ddb10..101fb2a 100644
--- a/third_party/polymer/v3_0/components-chromium/paper-ripple/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/paper-ripple/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v3_0/components-chromium/paper-spinner/BUILD.gn b/third_party/polymer/v3_0/components-chromium/paper-spinner/BUILD.gn
index 4d998d0..2a79df47 100644
--- a/third_party/polymer/v3_0/components-chromium/paper-spinner/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/paper-spinner/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,9 +7,7 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("paper-spinner-behavior") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
 
 js_library("paper-spinner-lite") {
diff --git a/third_party/polymer/v3_0/components-chromium/paper-styles/BUILD.gn b/third_party/polymer/v3_0/components-chromium/paper-styles/BUILD.gn
index 2c4b5bf1..7d81b54 100644
--- a/third_party/polymer/v3_0/components-chromium/paper-styles/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/paper-styles/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,9 +7,7 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("color") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
 
 js_library("default-theme") {
@@ -30,9 +28,7 @@
 }
 
 js_library("shadow") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
 
 js_library("typography") {
diff --git a/third_party/polymer/v3_0/components-chromium/paper-styles/classes/BUILD.gn b/third_party/polymer/v3_0/components-chromium/paper-styles/classes/BUILD.gn
index ced3624..121a3132 100644
--- a/third_party/polymer/v3_0/components-chromium/paper-styles/classes/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/paper-styles/classes/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -14,9 +14,7 @@
 }
 
 js_library("shadow") {
-  deps = [
-    "../../polymer:polymer_bundled",
-  ]
+  deps = [ "../../polymer:polymer_bundled" ]
 }
 
 js_library("typography") {
diff --git a/third_party/polymer/v3_0/components-chromium/paper-styles/element-styles/BUILD.gn b/third_party/polymer/v3_0/components-chromium/paper-styles/element-styles/BUILD.gn
index 00797a2d..b9b59d5 100644
--- a/third_party/polymer/v3_0/components-chromium/paper-styles/element-styles/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/paper-styles/element-styles/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
diff --git a/third_party/polymer/v3_0/components-chromium/paper-tooltip/BUILD.gn b/third_party/polymer/v3_0/components-chromium/paper-tooltip/BUILD.gn
index 7af0c00..f4b04ee 100644
--- a/third_party/polymer/v3_0/components-chromium/paper-tooltip/BUILD.gn
+++ b/third_party/polymer/v3_0/components-chromium/paper-tooltip/BUILD.gn
@@ -1,4 +1,4 @@
-# Copyright 2019 The Chromium Authors. All rights reserved.
+# 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.
 #
@@ -7,7 +7,5 @@
 import("//third_party/closure_compiler/compile_js.gni")
 
 js_library("paper-tooltip") {
-  deps = [
-    "../polymer:polymer_bundled",
-  ]
+  deps = [ "../polymer:polymer_bundled" ]
 }
diff --git a/tools/android/avd/avd.py b/tools/android/avd/avd.py
index 3236b0bc..eddb28a 100755
--- a/tools/android/avd/avd.py
+++ b/tools/android/avd/avd.py
@@ -81,11 +81,17 @@
   start_parser = subparsers.add_parser(
       'start',
       help='Start an AVD instance with the given config.')
+  start_parser.add_argument(
+      '--no-read-only',
+      action='store_false',
+      dest='read_only',
+      default=True,
+      help='Run a modifiable emulator. Will save snapshots on exit.')
   add_common_arguments(start_parser)
 
   def start_cmd(args):
     inst = avd.AvdConfig(args.avd_config).CreateInstance()
-    inst.Start(read_only=False, snapshot_save=True)
+    inst.Start(read_only=args.read_only, snapshot_save=not args.read_only)
     print('%s started (pid: %d)' % (str(inst), inst._emulator_proc.pid))
     return 0
 
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 84fce257..f2b82d8 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -26025,6 +26025,7 @@
   <int value="3136" label="CSPROWithReasonableRestrictions"/>
   <int value="3137" label="CSPWithBetterThanReasonableRestrictions"/>
   <int value="3138" label="CSPROWithBetterThanReasonableRestrictions"/>
+  <int value="3139" label="MeasureMemory"/>
 </enum>
 
 <enum name="FeaturePolicyAllowlistType">
@@ -36947,6 +36948,8 @@
   <int value="-1416754663" label="enable-mac-views-native-app-windows"/>
   <int value="-1416184931" label="TranslateRankerEnforcement:enabled"/>
   <int value="-1411733990" label="OmniboxDedupeGoogleDriveURLs:disabled"/>
+  <int value="-1411219910"
+      label="enable-experimental-accessibility-chromevox-annotations"/>
   <int value="-1411003295" label="disable-encrypted-media"/>
   <int value="-1410394131" label="EvDetailsInPageInfo:enabled"/>
   <int value="-1410001116"
@@ -56234,6 +56237,7 @@
   <int value="31" label="SENSITIVE_CONTENT_WARNING"/>
   <int value="32" label="SENSITIVE_CONTENT_BLOCK"/>
   <int value="33" label="DEEP_SCANNED_SAFE"/>
+  <int value="34" label="ADVANCED_PROTECTION_PROMPT"/>
 </enum>
 
 <enum name="SBClientDownloadCheckResult">
@@ -56250,6 +56254,7 @@
   <int value="10" label="SENSITIVE_CONTENT_WARNING"/>
   <int value="11" label="SENSITIVE_CONTENT_BLOCK"/>
   <int value="12" label="DEEP_SCANNED_SAFE"/>
+  <int value="13" label="PROMPT_FOR_SCANNING"/>
 </enum>
 
 <enum name="SBClientDownloadExtensions">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index eece7c6..a7bf5da1 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -48527,6 +48527,10 @@
 <histogram
     name="Extensions.DeclarativeNetRequest.EvaluateBeforeRequestTime.SingleExtension"
     units="ms" expires_after="2020-12-30">
+  <obsolete>
+    Deprecated Jan 2020 to increase resolution to microseconds. Replaced with
+    Extensions.DeclarativeNetRequest.EvaluateBeforeRequestTime.SingleExtension2.
+  </obsolete>
   <owner>karandeepb@chromium.org</owner>
   <owner>extensions-core@chromium.org</owner>
   <summary>
@@ -48537,6 +48541,19 @@
 </histogram>
 
 <histogram
+    name="Extensions.DeclarativeNetRequest.EvaluateBeforeRequestTime.SingleExtension2"
+    units="microseconds" expires_after="2021-01-31">
+  <owner>karandeepb@chromium.org</owner>
+  <owner>extensions-core@chromium.org</owner>
+  <summary>
+    Time taken to evaluate the before-request action for a network request for a
+    single extension ruleset. Emitted for each network request that is visible
+    to the extension. This is only emitted for users with high resolution
+    clocks.
+  </summary>
+</histogram>
+
+<histogram
     name="Extensions.DeclarativeNetRequest.EvaluateRequestTime.AllExtensions"
     units="ms" expires_after="M80">
   <obsolete>
@@ -48555,6 +48572,10 @@
 <histogram
     name="Extensions.DeclarativeNetRequest.EvaluateRequestTime.AllExtensions2"
     units="ms" expires_after="2020-12-30">
+  <obsolete>
+    Deprecated Jan 2020 to increase resolution to microseconds. Replaced with
+    Extensions.DeclarativeNetRequest.EvaluateRequestTime.AllExtensions3.
+  </obsolete>
   <owner>karandeepb@chromium.org</owner>
   <owner>extensions-core@chromium.org</owner>
   <summary>
@@ -48566,6 +48587,20 @@
   </summary>
 </histogram>
 
+<histogram
+    name="Extensions.DeclarativeNetRequest.EvaluateRequestTime.AllExtensions3"
+    units="microseconds" expires_after="2021-01-31">
+  <owner>karandeepb@chromium.org</owner>
+  <owner>extensions-core@chromium.org</owner>
+  <summary>
+    Time taken to evaluate the action to take for the network request as per the
+    Declarative Net Request API. This includes the time taken to evaluate all
+    the extension rulesets. Emitted for non-sensitive network requests seen by
+    the Extension System when there is at least one active extension ruleset.
+    This is only emitted for users with high resolution clocks.
+  </summary>
+</histogram>
+
 <histogram name="Extensions.DeclarativeNetRequest.IndexAndPersistRulesTime"
     units="ms" expires_after="2020-12-30">
   <owner>karandeepb@chromium.org</owner>
@@ -63205,7 +63240,7 @@
 </histogram>
 
 <histogram name="IOS.CommittedNavigationHasContext" enum="Boolean"
-    expires_after="2019-05-01">
+    expires_after="2020-08-01">
   <owner>danyao@chromium.org</owner>
   <summary>
     When a navigation is committed, it should have a non-null NavigationContext.
@@ -85731,10 +85766,10 @@
 </histogram>
 
 <histogram name="Net.NetworkErrorLogging.SignedExchangeRequestOutcome"
-    enum="NetNetworkErrorLoggingRequestOutcome" expires_after="2020-02-28">
+    enum="NetNetworkErrorLoggingRequestOutcome" expires_after="2020-10-01">
   <owner>horo@chromium.org</owner>
   <owner>ksakamoto@chromium.org</owner>
-  <owner>kouhei@chromium.org</owner>
+  <owner>kinuko@chromium.org</owner>
   <summary>
     When Network Error Logging observes a completed request of signed exchange
     that might generate a report, what happens to it. NEL observes all requests,
@@ -102061,7 +102096,7 @@
 </histogram>
 
 <histogram name="Omnibox.MatchStability.AsyncMatchChange2" units="position"
-    expires_after="2020-03-01">
+    expires_after="2021-03-01">
   <owner>tommycli@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <summary>
@@ -102463,7 +102498,7 @@
 </histogram>
 
 <histogram name="Omnibox.Start.WantAsyncMatches" enum="Boolean"
-    expires_after="2020-03-01">
+    expires_after="2021-03-01">
   <owner>tommycli@chromium.org</owner>
   <owner>jdonnelly@chromium.org</owner>
   <summary>
@@ -156342,7 +156377,7 @@
 </histogram>
 
 <histogram name="TabHoverCards.TabHoverCardsSeenBeforeTabSelection"
-    units="units" expires_after="2020-02-01">
+    units="units" expires_after="2020-05-01">
   <owner>corising@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
   <summary>
@@ -156352,7 +156387,7 @@
 </histogram>
 
 <histogram name="TabHoverCards.TimeSinceLastVisible" units="ms"
-    expires_after="2020-02-01">
+    expires_after="2020-05-01">
   <owner>corising@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
   <summary>
@@ -157697,7 +157732,7 @@
 </histogram>
 
 <histogram name="Tabs.ScrubbedInInterval.KeyPress" units="tabs"
-    expires_after="2020-02-01">
+    expires_after="2020-05-01">
   <owner>corising@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
   <summary>
@@ -157709,7 +157744,7 @@
 </histogram>
 
 <histogram name="Tabs.ScrubbedInInterval.MousePress" units="tabs"
-    expires_after="2020-02-01">
+    expires_after="2020-05-01">
   <owner>corising@chromium.org</owner>
   <owner>chrome-desktop-ui-sea@google.com</owner>
   <summary>
@@ -167940,7 +167975,7 @@
 </histogram>
 
 <histogram name="WebCore.Document.execCommand" enum="MappedEditingCommands"
-    expires_after="M81">
+    expires_after="2020-12-31">
   <owner>yoichio@chromium.org</owner>
   <summary>
     Counts the number of times each document.execCommand is executed. This
@@ -167949,7 +167984,7 @@
 </histogram>
 
 <histogram name="WebCore.Editing.Commands" enum="MappedEditingCommands"
-    expires_after="2020-07-01">
+    expires_after="2020-12-31">
   <owner>yoichio@chromium.org</owner>
   <summary>
     Counts the number of times each Editor::Command::execute is called. This
diff --git a/tools/metrics/structured/structured.xml b/tools/metrics/structured/structured.xml
index 05deb90..89f8198 100644
--- a/tools/metrics/structured/structured.xml
+++ b/tools/metrics/structured/structured.xml
@@ -2,22 +2,29 @@
 
 <!-- Structured metrics is under development and isn't available for use yet. -->
 
-<event name="TestEvent">
+<event name="TestEventOne">
   <owner>tby@chromium.org</owner>
   <summary>
     Event for unit testing, do not use.
   </summary>
-  <metric name="ValueOne" kind="hashed-string">
+  <metric name="TestMetricOne" kind="hashed-string">
     <summary>
       A per-user keyed hashed value.
     </summary>
   </metric>
-  <metric name="ValueThree" kind="int">
+  <metric name="TestMetricTwo" kind="int">
     <summary>
       An unhashed value, recorded as-is.
     </summary>
   </metric>
-  <metric name="ValueTwo" kind="hashed-string">
+</event>
+
+<event name="TestEventTwo">
+  <owner>tby@chromium.org</owner>
+  <summary>
+    Event for unit testing, do not use.
+  </summary>
+  <metric name="TestMetricOne" kind="hashed-string">
     <summary>
       A per-user keyed hashed value.
     </summary>
diff --git a/ui/accessibility/accessibility_switches.cc b/ui/accessibility/accessibility_switches.cc
index 3d2e14a..41d5507 100644
--- a/ui/accessibility/accessibility_switches.cc
+++ b/ui/accessibility/accessibility_switches.cc
@@ -41,6 +41,10 @@
 const char kEnableExperimentalAccessibilitySwitchAccessText[] =
     "enable-experimental-accessibility-switch-access-text";
 
+// Enables annotations feature that hasn't launched yet.
+const char kEnableExperimentalAccessibilityChromeVoxAnnotations[] =
+    "enable-experimental-accessibility-chromevox-annotations";
+
 // Enables language switching feature that hasn't launched yet.
 const char kEnableExperimentalAccessibilityChromeVoxLanguageSwitching[] =
     "enable-experimental-accessibility-chromevox-language-switching";
diff --git a/ui/accessibility/accessibility_switches.h b/ui/accessibility/accessibility_switches.h
index ffb6ac9..d0391a64 100644
--- a/ui/accessibility/accessibility_switches.h
+++ b/ui/accessibility/accessibility_switches.h
@@ -20,6 +20,8 @@
 AX_EXPORT extern const char kEnableExperimentalAccessibilitySwitchAccess[];
 AX_EXPORT extern const char kEnableExperimentalAccessibilitySwitchAccessText[];
 AX_EXPORT extern const char
+    kEnableExperimentalAccessibilityChromeVoxAnnotations[];
+AX_EXPORT extern const char
     kEnableExperimentalAccessibilityChromeVoxLanguageSwitching[];
 AX_EXPORT extern const char
     kEnableExperimentalAccessibilityChromeVoxSearchMenus[];
diff --git a/ui/base/ime/win/tsf_text_store.cc b/ui/base/ime/win/tsf_text_store.cc
index 88e321d07..ed02804 100644
--- a/ui/base/ime/win/tsf_text_store.cc
+++ b/ui/base/ime/win/tsf_text_store.cc
@@ -609,6 +609,12 @@
   if (string_pending_insertion_.empty()) {
     if (!text_input_client_->HasCompositionText()) {
       if (has_composition_range_) {
+        // Remove replacing text first before starting composition.
+        if (new_text_inserted_ && !replace_text_range_.is_empty() &&
+            !replace_text_size_) {
+          text_input_client_->SetEditableSelectionRange(replace_text_range_);
+          text_input_client_->ExtendSelectionAndDelete(0, 0);
+        }
         string_pending_insertion_ = string_buffer_document_.substr(
             composition_range_.GetMin(), composition_range_.length());
         StartCompositionOnExistingText();
@@ -791,7 +797,7 @@
     return ret;
 
   TS_TEXTCHANGE change;
-  if (text_buffer_size > 0) {
+  if (text_buffer_size >= 0) {
     new_text_inserted_ = true;
     replace_text_range_.set_start(acp_start);
     replace_text_range_.set_end(acp_end);
diff --git a/ui/base/ime/win/tsf_text_store_unittest.cc b/ui/base/ime/win/tsf_text_store_unittest.cc
index 7cb99f74..aefd640 100644
--- a/ui/base/ime/win/tsf_text_store_unittest.cc
+++ b/ui/base/ime/win/tsf_text_store_unittest.cc
@@ -3295,5 +3295,105 @@
   EXPECT_EQ(S_OK, result);
 }
 
+// regression tests for crbug.com/1013154.
+// We should remove selected text before start composition on existing text.
+class RegressionTest7Callback : public TSFTextStoreTestCallback {
+ public:
+  explicit RegressionTest7Callback(TSFTextStore* text_store)
+      : TSFTextStoreTestCallback(text_store) {}
+
+  HRESULT LockGranted1(DWORD flags) {
+    SetTextTest(0, 0, L"aaaa", S_OK);
+    SetSelectionTest(0, 4, S_OK);
+    return S_OK;
+  }
+
+  HRESULT LockGranted2(DWORD flags) {
+    GetTextTest(0, -1, L"aaaa", 4);
+    SetTextTest(1, 4, L"", S_OK);
+    SetSelectionTest(1, 1, S_OK);
+
+    text_spans()->clear();
+    ImeTextSpan text_span_1;
+    text_span_1.start_offset = 0;
+    text_span_1.end_offset = 1;
+    text_span_1.underline_color = SK_ColorBLACK;
+    text_span_1.thickness = ImeTextSpan::Thickness::kThin;
+    text_span_1.background_color = SK_ColorTRANSPARENT;
+    text_spans()->push_back(text_span_1);
+
+    *edit_flag() = true;
+    *composition_start() = 0;
+    composition_range()->set_start(0);
+    composition_range()->set_end(1);
+    *has_composition_range() = true;
+
+    text_store_->OnKeyTraceDown(65u, 1966081u);
+    return S_OK;
+  }
+
+  bool SetCompositionFromExistingText2(
+      const gfx::Range& range,
+      const std::vector<ui::ImeTextSpan>& text_spans) {
+    EXPECT_EQ(0u, range.start());
+    EXPECT_EQ(1u, range.end());
+    EXPECT_EQ(1u, text_spans.size());
+    SetHasCompositionText(true);
+    return true;
+  }
+
+  HRESULT LockGranted3(DWORD flags) {
+    GetTextTest(0, -1, L"a", 1);
+
+    text_spans()->clear();
+    *edit_flag() = true;
+    *composition_start() = 1;
+    composition_range()->set_start(0);
+    composition_range()->set_end(0);
+
+    *has_composition_range() = false;
+    text_store_->OnKeyTraceUp(65u, 1966081u);
+    return S_OK;
+  }
+
+  void InsertText3(const base::string16& text) {
+    EXPECT_EQ(L"a", text);
+    SetHasCompositionText(false);
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RegressionTest7Callback);
+};
+
+TEST_F(TSFTextStoreTest, RegressionTest7) {
+  RegressionTest7Callback callback(text_store_.get());
+  EXPECT_CALL(text_input_client_, SetCompositionFromExistingText(_, _))
+      .WillOnce(
+          Invoke(&callback,
+                 &RegressionTest7Callback::SetCompositionFromExistingText2));
+
+  EXPECT_CALL(text_input_client_, InsertText(_))
+      .WillOnce(Invoke(&callback, &RegressionTest7Callback::InsertText3));
+
+  EXPECT_CALL(*sink_, OnLockGranted(_))
+      .WillOnce(Invoke(&callback, &RegressionTest7Callback::LockGranted1))
+      .WillOnce(Invoke(&callback, &RegressionTest7Callback::LockGranted2))
+      .WillOnce(Invoke(&callback, &RegressionTest7Callback::LockGranted3));
+
+  ON_CALL(text_input_client_, HasCompositionText())
+      .WillByDefault(
+          Invoke(&callback, &TSFTextStoreTestCallback::HasCompositionText));
+
+  HRESULT result = kInvalidResult;
+  EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result));
+  EXPECT_EQ(S_OK, result);
+  result = kInvalidResult;
+  EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result));
+  EXPECT_EQ(S_OK, result);
+  result = kInvalidResult;
+  EXPECT_EQ(S_OK, text_store_->RequestLock(TS_LF_READWRITE, &result));
+  EXPECT_EQ(S_OK, result);
+}
+
 }  // namespace
 }  // namespace ui
diff --git a/ui/base/x/x11_shm_image_pool_base.cc b/ui/base/x/x11_shm_image_pool_base.cc
index 9baf516..39ec3b9 100644
--- a/ui/base/x/x11_shm_image_pool_base.cc
+++ b/ui/base/x/x11_shm_image_pool_base.cc
@@ -194,16 +194,16 @@
       if (state.shminfo_.shmid < 0)
         return false;
       state.shminfo_.shmaddr =
-          reinterpret_cast<char*>(shmat(state.shminfo_.shmid, 0, 0));
+          reinterpret_cast<char*>(shmat(state.shminfo_.shmid, nullptr, 0));
       if (state.shminfo_.shmaddr == reinterpret_cast<char*>(-1)) {
-        shmctl(state.shminfo_.shmid, IPC_RMID, 0);
+        shmctl(state.shminfo_.shmid, IPC_RMID, nullptr);
         return false;
       }
 #if defined(OS_LINUX)
       // On Linux, a shmid can still be attached after IPC_RMID if otherwise
       // kept alive.  Detach before XShmAttach to prevent a memory leak in case
       // the process dies.
-      shmctl(state.shminfo_.shmid, IPC_RMID, 0);
+      shmctl(state.shminfo_.shmid, IPC_RMID, nullptr);
 #endif
       DCHECK(!state.shmem_attached_to_server_);
       if (!XShmAttach(display_, &state.shminfo_))
@@ -214,7 +214,7 @@
       // forced to do IPC_RMID after the server has attached to the segment.
       // XShmAttach is asynchronous, so we must also sync.
       XSync(display_, x11::False);
-      shmctl(shminfo_.shmid, IPC_RMID, 0);
+      shmctl(shminfo_.shmid, IPC_RMID, nullptr);
 #endif
       // If this class ever needs to use XShmGetImage(), this needs to be
       // changed to read-write.
@@ -222,8 +222,7 @@
     }
   }
 
-  for (std::size_t i = 0; i < frame_states_.size(); ++i) {
-    FrameState& state = frame_states_[i];
+  for (FrameState& state : frame_states_) {
     state.image->data = state.shminfo_.shmaddr;
     SkImageInfo image_info =
         SkImageInfo::Make(state.image->width, state.image->height,
diff --git a/ui/webui/resources/cr_elements/BUILD.gn b/ui/webui/resources/cr_elements/BUILD.gn
index 656410d..4f7a14c 100644
--- a/ui/webui/resources/cr_elements/BUILD.gn
+++ b/ui/webui/resources/cr_elements/BUILD.gn
@@ -181,7 +181,7 @@
     "cr_toolbar:cr_toolbar_search_field_module",
     "cr_toolbar:cr_toolbar_selection_overlay_module",
     "cr_view_manager:cr_view_manager_module",
-    "policy:cr_tooltip_icon_module",
+    "policy:polymer3_elements",
   ]
 
   if (is_chromeos) {
diff --git a/ui/webui/resources/cr_elements/cr_slider/BUILD.gn b/ui/webui/resources/cr_elements/cr_slider/BUILD.gn
index 379930f3..1229cf7 100644
--- a/ui/webui/resources/cr_elements/cr_slider/BUILD.gn
+++ b/ui/webui/resources/cr_elements/cr_slider/BUILD.gn
@@ -22,6 +22,7 @@
   html_file = "cr_slider.html"
   html_type = "dom-module"
   auto_imports = [ "ui/webui/resources/html/event_tracker.html|EventTracker" ]
+  namespace_rewrites = [ "cr_slider.SliderTick|SliderTick" ]
 }
 
 js_type_check("closure_compile_module") {
@@ -36,7 +37,6 @@
   deps = [
     "//third_party/polymer/v3_0/components-chromium/paper-behaviors:paper-ripple-behavior",
     "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
-    "//ui/webui/resources/js:cr.m",
     "//ui/webui/resources/js:event_tracker.m",
   ]
   extra_deps = [ ":cr_slider_module" ]
diff --git a/ui/webui/resources/cr_elements/cr_slider/cr_slider.js b/ui/webui/resources/cr_elements/cr_slider/cr_slider.js
index 5e1f94d8..4d77f318 100644
--- a/ui/webui/resources/cr_elements/cr_slider/cr_slider.js
+++ b/ui/webui/resources/cr_elements/cr_slider/cr_slider.js
@@ -19,7 +19,7 @@
    *   ariaValue: (number|undefined),
    * }}
    */
-  let SliderTick;
+  /* #export */ let SliderTick;
 
   /**
    * @param {number} min
@@ -32,9 +32,7 @@
   }
 
   /**
-   * Object is actually a SliderTick, but the closure compiler won't
-   * recognise it with the way this code is structured.
-   * @param {!(Object|number)} tick
+   * @param {!(cr_slider.SliderTick|number)} tick
    * @return {number}
    */
   function getAriaValue(tick) {
@@ -124,9 +122,7 @@
       /**
        * The data associated with each tick on the slider. Each element in the
        * array contains a value and the label corresponding to that value.
-       * Object is actually a SliderTick, but the closure compiler won't
-       * recognise it with the way this code is structured.
-       * @type {!Array<Object>|!Array<number>}
+       * @type {!Array<cr_slider.SliderTick>|!Array<number>}
        */
       ticks: {
         type: Array,
diff --git a/ui/webui/resources/cr_elements/policy/BUILD.gn b/ui/webui/resources/cr_elements/policy/BUILD.gn
index c1c2741..d74cac4 100644
--- a/ui/webui/resources/cr_elements/policy/BUILD.gn
+++ b/ui/webui/resources/cr_elements/policy/BUILD.gn
@@ -4,6 +4,7 @@
 
 import("//third_party/closure_compiler/compile_js.gni")
 import("//tools/polymer/polymer.gni")
+import("../../tools/js_modulizer.gni")
 
 js_type_check("closure_compile") {
   deps = [
@@ -65,15 +66,30 @@
 js_library("cr_tooltip_icon") {
 }
 
-polymer_modulizer("cr_tooltip_icon") {
-  js_file = "cr_tooltip_icon.js"
-  html_file = "cr_tooltip_icon.html"
-  html_type = "dom-module"
-}
+# Polymer 3 autogenerated version
 
 js_type_check("closure_compile_module") {
   is_polymer3 = true
-  deps = [ ":cr_tooltip_icon.m" ]
+  deps = [
+    ":cr_policy_indicator.m",
+    ":cr_policy_indicator_behavior.m",
+    ":cr_tooltip_icon.m",
+  ]
+}
+
+js_library("cr_policy_indicator.m") {
+  sources = [ "$root_gen_dir/ui/webui/resources/cr_elements/policy/cr_policy_indicator.m.js" ]
+  deps = [
+    ":cr_policy_indicator_behavior.m",
+    "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+  ]
+  extra_deps = [ ":cr_policy_indicator_module" ]
+}
+
+js_library("cr_policy_indicator_behavior.m") {
+  sources = [ "$root_gen_dir/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.m.js" ]
+  deps = [ "//ui/webui/resources/js:assert.m" ]
+  extra_deps = [ ":modulize" ]
 }
 
 js_library("cr_tooltip_icon.m") {
@@ -85,3 +101,28 @@
   ]
   extra_deps = [ ":cr_tooltip_icon_module" ]
 }
+
+group("polymer3_elements") {
+  deps = [
+    ":cr_policy_indicator_module",
+    ":cr_tooltip_icon_module",
+    ":modulize",
+  ]
+}
+
+polymer_modulizer("cr_policy_indicator") {
+  js_file = "cr_policy_indicator.js"
+  html_file = "cr_policy_indicator.html"
+  html_type = "dom-module"
+  auto_imports = [ "ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.html|CrPolicyIndicatorBehavior,CrPolicyIndicatorType" ]
+}
+
+polymer_modulizer("cr_tooltip_icon") {
+  js_file = "cr_tooltip_icon.js"
+  html_file = "cr_tooltip_icon.html"
+  html_type = "dom-module"
+}
+
+js_modulizer("modulize") {
+  input_files = [ "cr_policy_indicator_behavior.js" ]
+}
diff --git a/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js b/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js
index 6f99752f..1655bad 100644
--- a/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js
+++ b/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js
@@ -8,6 +8,8 @@
  * rework the "policy" naming scheme throughout this directory.
  */
 
+// #import {assertNotReached} from 'chrome://resources/js/assert.m.js';
+
 /**
  * Strings required for policy indicators. These must be set at runtime.
  * Chrome OS only strings may be undefined.
@@ -28,7 +30,7 @@
 var CrPolicyStrings;
 
 /** @enum {string} */
-const CrPolicyIndicatorType = {
+/* #export */ const CrPolicyIndicatorType = {
   DEVICE_POLICY: 'devicePolicy',
   EXTENSION: 'extension',
   NONE: 'none',
@@ -41,7 +43,7 @@
 };
 
 /** @polymerBehavior */
-const CrPolicyIndicatorBehavior = {
+/* #export */ const CrPolicyIndicatorBehavior = {
   // Properties exposed to all policy indicators.
   properties: {
     /**
@@ -121,9 +123,11 @@
    * @return {string} The tooltip text for |type|.
    */
   getIndicatorTooltip(type, name, opt_matches) {
-    if (!CrPolicyStrings) {
+    if (!window['CrPolicyStrings']) {
       return '';
     }  // Tooltips may not be defined, e.g. in OOBE.
+
+    CrPolicyStrings = window['CrPolicyStrings'];
     switch (type) {
       case CrPolicyIndicatorType.EXTENSION:
         return name.length > 0 ?
diff --git a/ui/webui/resources/cr_elements_resources_v3.grdp b/ui/webui/resources/cr_elements_resources_v3.grdp
index 88348e8..0e78e0b 100644
--- a/ui/webui/resources/cr_elements_resources_v3.grdp
+++ b/ui/webui/resources/cr_elements_resources_v3.grdp
@@ -116,6 +116,11 @@
          use_base_dir="false"
          type="BINDATA"
          compress="gzip" />
+  <include name="IDR_CR_ELEMENTS_CR_SLIDER_M_JS"
+         file="${root_gen_dir}/ui/webui/resources/cr_elements/cr_slider/cr_slider.m.js"
+         use_base_dir="false"
+         type="BINDATA"
+         compress="gzip" />
   <include name="IDR_CR_ELEMENTS_CR_SPLITTER_JS"
          file="cr_elements/cr_splitter/cr_splitter.js"
          type="BINDATA"
@@ -155,11 +160,21 @@
          use_base_dir="false"
          type="BINDATA"
          compress="gzip" />
-  <include name="IDR_CR_ELEMENTS_CR_TOOLTIP_ICON_M_JS"
+  <include name="IDR_CR_ELEMENTS_POLICY_CR_TOOLTIP_ICON_M_JS"
          file="${root_gen_dir}/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.m.js"
          use_base_dir="false"
          type="BINDATA"
          compress="gzip" />
+  <include name="IDR_CR_ELEMENTS_POLICY_CR_POLICY_INDICATOR_M_JS"
+         file="${root_gen_dir}/ui/webui/resources/cr_elements/policy/cr_policy_indicator.m.js"
+         use_base_dir="false"
+         type="BINDATA"
+         compress="gzip" />
+  <include name="IDR_CR_ELEMENTS_POLICY_CR_POLICY_INDICATOR_BEHAVIOR_M_JS"
+         file="${root_gen_dir}/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.m.js"
+         use_base_dir="false"
+         type="BINDATA"
+         compress="gzip" />
   <include name="IDR_CR_ELEMENTS_CR_VIEW_MANAGER_M_JS"
          file="${root_gen_dir}/ui/webui/resources/cr_elements/cr_view_manager/cr_view_manager.m.js"
          use_base_dir="false"
@@ -185,11 +200,6 @@
          use_base_dir="false"
          type="BINDATA"
          compress="gzip" />
-  <include name="IDR_CR_ELEMENTS_CR_SLIDER_M_JS"
-         file="${root_gen_dir}/ui/webui/resources/cr_elements/cr_slider/cr_slider.m.js"
-         use_base_dir="false"
-         type="BINDATA"
-         compress="gzip" />
   <if expr="chromeos">
     <include name="IDR_CR_ELEMENTS_CR_SEARCHABLE_DROP_DOWN_M_JS"
            file="${root_gen_dir}/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.m.js"