diff --git a/DEPS b/DEPS
index e730c080..8b15587 100644
--- a/DEPS
+++ b/DEPS
@@ -213,7 +213,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'spv_tools_revision': 'b27d084b0112ca7e33262dabffe5b88dbad56673',
+  'spv_tools_revision': '21bcb9d8b9dba1c7b7e1d0a8f5b6ad7ea26cc5b6',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
@@ -604,7 +604,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '01f0c698fb898168940718c5616ed3f6bb6c1b18',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '0f5a0b4409892f575b559ca77bd9369650bd2443',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1098,7 +1098,7 @@
     Var('chromium_git') + '/external/khronosgroup/webgl.git' + '@' + '7ca87fb1d3da3b3d2060886e8c58e726d74c8219',
 
   'src/third_party/webrtc':
-    Var('webrtc_git') + '/src.git' + '@' + 'b9bb9e3f6683a74acab9198359d17a3b68644338',
+    Var('webrtc_git') + '/src.git' + '@' + 'bb081a62dc30a49fa77cfdbb4ae470c5137fa547',
 
   'src/third_party/xdg-utils': {
       'url': Var('chromium_git') + '/chromium/deps/xdg-utils.git' + '@' + 'd80274d5869b17b8c9067a1022e4416ee7ed5e0d',
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index dbfbfb2a..58d96c0 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -2289,6 +2289,8 @@
     "wm/lock_state_controller_test_api.h",
     "wm/splitview/split_view_highlight_view_test_api.cc",
     "wm/splitview/split_view_highlight_view_test_api.h",
+    "wm/tablet_mode/tablet_mode_controller_test_api.cc",
+    "wm/tablet_mode/tablet_mode_controller_test_api.h",
     "wm/test_activation_delegate.cc",
     "wm/test_activation_delegate.h",
     "wm/test_child_modal_parent.cc",
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc
index d40f3d7..c45f116 100644
--- a/ash/app_list/app_list_controller_impl.cc
+++ b/ash/app_list/app_list_controller_impl.cc
@@ -503,12 +503,23 @@
   if (!IsHomeLauncherEnabledInTabletMode())
     return;
 
-  // Only animate the app list when overview mode is using slide animation.
-  presenter_.ScheduleOverviewModeAnimation(
-      false /* start */, Shell::Get()
-                             ->window_selector_controller()
-                             ->window_selector()
-                             ->use_slide_animation() /* animate */);
+  // Animate the launcher if overview mode is sliding out. Let
+  // OnOverviewModeEndingAnimationComplete handle showing the launcher after
+  // overview mode finishes animating. WindowSelector however is nullptr by the
+  // time the animations are finished, so we need to check the animation type
+  // here.
+  use_slide_to_exit_overview_mode_ = Shell::Get()
+                                         ->window_selector_controller()
+                                         ->window_selector()
+                                         ->use_slide_animation();
+}
+
+void AppListControllerImpl::OnOverviewModeEndingAnimationComplete() {
+  if (!IsHomeLauncherEnabledInTabletMode())
+    return;
+
+  presenter_.ScheduleOverviewModeAnimation(/*start=*/false,
+                                           use_slide_to_exit_overview_mode_);
 }
 
 void AppListControllerImpl::OnTabletModeStarted() {
diff --git a/ash/app_list/app_list_controller_impl.h b/ash/app_list/app_list_controller_impl.h
index de8a3397..44776b1 100644
--- a/ash/app_list/app_list_controller_impl.h
+++ b/ash/app_list/app_list_controller_impl.h
@@ -188,6 +188,7 @@
   // ShellObserver:
   void OnOverviewModeStarting() override;
   void OnOverviewModeEnding() override;
+  void OnOverviewModeEndingAnimationComplete() override;
 
   // TabletModeObserver:
   void OnTabletModeStarted() override;
@@ -267,6 +268,11 @@
   // should be hidden during overview mode.
   bool in_overview_mode_ = false;
 
+  // Each time overview mode is exited, set this variable based on whether
+  // overview mode is sliding out, so the home launcher knows what to do when
+  // overview mode exit animations are finished.
+  bool use_slide_to_exit_overview_mode_ = false;
+
   // Whether the wallpaper is being previewed. The home launcher (if enabled)
   // should be hidden during wallpaper preview.
   bool in_wallpaper_preview_ = false;
diff --git a/ash/app_list/presenter/app_list_presenter_impl.cc b/ash/app_list/presenter/app_list_presenter_impl.cc
index efc16d4..e3bf6423 100644
--- a/ash/app_list/presenter/app_list_presenter_impl.cc
+++ b/ash/app_list/presenter/app_list_presenter_impl.cc
@@ -35,10 +35,6 @@
 // The y offset for app list animation when overview mode toggles.
 constexpr int kOverviewAnimationYOffset = 100;
 
-// The delay in milliseconds for app list animation when overview mode ends
-constexpr base::TimeDelta kOverviewEndAnimationDelay =
-    base::TimeDelta::FromMilliseconds(250);
-
 // The duration in milliseconds for app list animation when overview mode
 // toggles.
 constexpr base::TimeDelta kOverviewAnimationDuration =
@@ -48,8 +44,7 @@
   return widget->GetNativeView()->layer();
 }
 
-void UpdateOverviewSettings(bool end_overview,
-                            ui::AnimationMetricsReporter* reporter,
+void UpdateOverviewSettings(ui::AnimationMetricsReporter* reporter,
                             ui::ScopedLayerAnimationSettings* settings) {
   settings->SetTransitionDuration(kOverviewAnimationDuration);
   settings->SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN);
@@ -58,13 +53,6 @@
 
   DCHECK(reporter);
   settings->SetAnimationMetricsReporter(reporter);
-
-  if (end_overview) {
-    settings->GetAnimator()->SchedulePauseForProperties(
-        kOverviewEndAnimationDelay,
-        ui::LayerAnimationElement::AnimatableProperty::OPACITY |
-            ui::LayerAnimationElement::AnimatableProperty::TRANSFORM);
-  }
 }
 
 class StateAnimationMetricsReporter : public ui::AnimationMetricsReporter {
@@ -270,7 +258,7 @@
   }
   UpdateYPositionAndOpacityForHomeLauncher(
       start ? kOverviewAnimationYOffset : 0, start ? 0.f : 1.f,
-      animate ? base::BindRepeating(&UpdateOverviewSettings, start,
+      animate ? base::BindRepeating(&UpdateOverviewSettings,
                                     state_animation_metrics_reporter_.get())
               : base::NullCallback());
 }
diff --git a/ash/app_list/views/search_result_view.cc b/ash/app_list/views/search_result_view.cc
index 1bf350c..7dc5e6e 100644
--- a/ash/app_list/views/search_result_view.cc
+++ b/ash/app_list/views/search_result_view.cc
@@ -62,16 +62,13 @@
     : list_view_(list_view),
       view_delegate_(view_delegate),
       icon_(new views::ImageView),
-      badge_icon_(new views::ImageView),
       actions_view_(new SearchResultActionsView(this)),
       progress_bar_(new views::ProgressBar),
       weak_ptr_factory_(this) {
   SetFocusBehavior(FocusBehavior::ALWAYS);
   icon_->set_can_process_events_within_subtree(false);
-  badge_icon_->set_can_process_events_within_subtree(false);
 
   AddChildView(icon_);
-  AddChildView(badge_icon_);
   AddChildView(actions_view_);
   AddChildView(progress_bar_);
   set_context_menu_controller(this);
@@ -208,17 +205,6 @@
   icon_bounds.Intersect(rect);
   icon_->SetBoundsRect(icon_bounds);
 
-  gfx::Rect badge_icon_bounds;
-
-  const int badge_icon_dimension =
-      AppListConfig::instance().search_list_badge_icon_dimension();
-  badge_icon_bounds = gfx::Rect(icon_bounds.right() - badge_icon_dimension / 2,
-                                icon_bounds.bottom() - badge_icon_dimension / 2,
-                                badge_icon_dimension, badge_icon_dimension);
-
-  badge_icon_bounds.Intersect(rect);
-  badge_icon_->SetBoundsRect(badge_icon_bounds);
-
   const int max_actions_width =
       (rect.right() - kActionButtonRightMargin - icon_bounds.right()) / 2;
   int actions_width =
@@ -352,17 +338,6 @@
     SetIconImage(icon, icon_,
                  AppListConfig::instance().search_list_icon_dimension());
 
-  // Updates |badge_icon_|.
-  const gfx::ImageSkia badge_icon(result_ ? result_->badge_icon()
-                                          : gfx::ImageSkia());
-  if (badge_icon.isNull()) {
-    badge_icon_->SetVisible(false);
-  } else {
-    SetIconImage(badge_icon, badge_icon_,
-                 AppListConfig::instance().search_list_badge_icon_dimension());
-    badge_icon_->SetVisible(true);
-  }
-
   // Updates |actions_view_|.
   actions_view_->SetActions(result_ ? result_->actions()
                                     : SearchResult::Actions());
diff --git a/ash/app_list/views/search_result_view.h b/ash/app_list/views/search_result_view.h
index bbc5b70..41e748d 100644
--- a/ash/app_list/views/search_result_view.h
+++ b/ash/app_list/views/search_result_view.h
@@ -131,7 +131,6 @@
   AppListViewDelegate* view_delegate_;
 
   views::ImageView* icon_;        // Owned by views hierarchy.
-  views::ImageView* badge_icon_;  // Owned by views hierarchy.
   std::unique_ptr<gfx::RenderText> title_text_;
   std::unique_ptr<gfx::RenderText> details_text_;
   SearchResultActionsView* actions_view_;  // Owned by the views hierarchy.
diff --git a/ash/assistant/ui/main_stage/ui_element_container_view.cc b/ash/assistant/ui/main_stage/ui_element_container_view.cc
index 69ad6d6..88885ea 100644
--- a/ash/assistant/ui/main_stage/ui_element_container_view.cc
+++ b/ash/assistant/ui/main_stage/ui_element_container_view.cc
@@ -291,9 +291,13 @@
   for (const std::pair<ui::LayerOwner*, float>& pair : ui_element_views_) {
     StartLayerAnimationSequence(
         pair.first->layer()->GetAnimator(),
-        // Fade out the opacity to 0%.
+        // Fade out the opacity to 0%. Note that we approximate 0% by actually
+        // using 0.01%. We do this to workaround a DCHECK that requires
+        // aura::Windows to have a target opacity > 0% when shown. Because our
+        // window will be removed after it reaches this value, it should be safe
+        // to circumnavigate this DCHECK.
         CreateLayerAnimationSequence(
-            CreateOpacityElement(0.f, kUiElementAnimationFadeOutDuration)),
+            CreateOpacityElement(0.0001f, kUiElementAnimationFadeOutDuration)),
         // Observe the animation.
         ui_elements_exit_animation_observer_.get());
   }
@@ -465,9 +469,13 @@
     view_holder->Attach();
 
     // The view will be animated on its own layer, so we need to do some initial
-    // layer setup. We're going to fade the view in, so hide it.
+    // layer setup. We're going to fade the view in, so hide it. Note that we
+    // approximate 0% opacity by actually using 0.01%. We do this to workaround
+    // a DCHECK that requires aura::Windows to have a target opacity > 0% when
+    // shown. Because our window will be animated to full opacity from this
+    // value, it should be safe to circumnavigate this DCHECK.
     view_holder->native_view()->layer()->SetFillsBoundsOpaquely(false);
-    view_holder->native_view()->layer()->SetOpacity(0.f);
+    view_holder->native_view()->layer()->SetOpacity(0.0001f);
 
     // We cache the native view for use during animations and its desired
     // opacity that we'll animate to while processing the next query response.
diff --git a/ash/keyboard/virtual_keyboard_controller.cc b/ash/keyboard/virtual_keyboard_controller.cc
index 623d4f38..aefff26 100644
--- a/ash/keyboard/virtual_keyboard_controller.cc
+++ b/ash/keyboard/virtual_keyboard_controller.cc
@@ -124,20 +124,8 @@
                              base::Unretained(this)));
 }
 
-void VirtualKeyboardController::OnTabletModeStarted() {
-  if (IsVirtualKeyboardEnabled()) {
-    SetKeyboardEnabled(true);
-  } else {
-    UpdateKeyboardEnabled();
-  }
-}
-
-void VirtualKeyboardController::OnTabletModeEnded() {
-  if (IsVirtualKeyboardEnabled()) {
-    SetKeyboardEnabled(false);
-  } else {
-    UpdateKeyboardEnabled();
-  }
+void VirtualKeyboardController::OnTabletModeEventsBlockingChanged() {
+  UpdateKeyboardEnabled();
 }
 
 void VirtualKeyboardController::OnTouchscreenDeviceConfigurationChanged() {
@@ -236,12 +224,12 @@
   if (IsVirtualKeyboardEnabled()) {
     SetKeyboardEnabled(Shell::Get()
                            ->tablet_mode_controller()
-                           ->IsTabletModeWindowManagerEnabled());
+                           ->AreInternalInputDeviceEventsBlocked());
     return;
   }
   bool ignore_internal_keyboard = Shell::Get()
                                       ->tablet_mode_controller()
-                                      ->IsTabletModeWindowManagerEnabled();
+                                      ->AreInternalInputDeviceEventsBlocked();
   bool is_internal_keyboard_active =
       has_internal_keyboard_ && !ignore_internal_keyboard;
   SetKeyboardEnabled(!is_internal_keyboard_active && has_touchscreen_ &&
diff --git a/ash/keyboard/virtual_keyboard_controller.h b/ash/keyboard/virtual_keyboard_controller.h
index 2664653..5ad4c51a 100644
--- a/ash/keyboard/virtual_keyboard_controller.h
+++ b/ash/keyboard/virtual_keyboard_controller.h
@@ -38,9 +38,7 @@
       chromeos::input_method::mojom::ImeKeyset keyset);
 
   // TabletModeObserver:
-  // TODO(rsadam@): Remove when autovirtual keyboard flag is on by default.
-  void OnTabletModeStarted() override;
-  void OnTabletModeEnded() override;
+  void OnTabletModeEventsBlockingChanged() override;
 
   // ui::InputDeviceObserver:
   void OnTouchscreenDeviceConfigurationChanged() override;
@@ -50,7 +48,7 @@
   // when determining whether or not to show the on-screen keyboard.
   void ToggleIgnoreExternalKeyboard();
 
-  // keyboard::KeyboardLayoutDelegate
+  // keyboard::KeyboardLayoutDelegate:
   void MoveKeyboardToDisplay(const display::Display& display) override;
   void MoveKeyboardToTouchableDisplay() override;
 
diff --git a/ash/keyboard/virtual_keyboard_controller_unittest.cc b/ash/keyboard/virtual_keyboard_controller_unittest.cc
index a1c3a89..97b4027 100644
--- a/ash/keyboard/virtual_keyboard_controller_unittest.cc
+++ b/ash/keyboard/virtual_keyboard_controller_unittest.cc
@@ -16,6 +16,7 @@
 #include "ash/test/ash_test_base.h"
 #include "ash/wm/tablet_mode/scoped_disable_internal_mouse_and_keyboard.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
 #include "base/command_line.h"
 #include "services/ws/public/cpp/input_devices/input_device_client_test_api.h"
 #include "ui/display/test/display_manager_test_api.h"
@@ -43,12 +44,6 @@
   VirtualKeyboardControllerTest() = default;
   ~VirtualKeyboardControllerTest() override = default;
 
-  // Sets the event blocker on the maximized window controller.
-  void SetEventBlocker(
-      std::unique_ptr<ScopedDisableInternalMouseAndKeyboard> blocker) {
-    Shell::Get()->tablet_mode_controller()->event_blocker_ = std::move(blocker);
-  }
-
   void SetUp() override {
     AshTestBase::SetUp();
     ws::InputDeviceClientTestApi().SetKeyboardDevices({});
@@ -105,7 +100,7 @@
   Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
   std::unique_ptr<ScopedDisableInternalMouseAndKeyboard> blocker(
       new MockEventBlocker);
-  SetEventBlocker(std::move(blocker));
+  TabletModeControllerTestApi().set_event_blocker(std::move(blocker));
 }
 
 TEST_F(VirtualKeyboardControllerTest,
@@ -359,15 +354,15 @@
   ws::InputDeviceClientTestApi().SetKeyboardDevices(keyboard_devices);
   ASSERT_FALSE(keyboard::IsKeyboardEnabled());
   // Toggle tablet mode on.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  TabletModeControllerTestApi().EnterTabletMode();
   ASSERT_TRUE(keyboard::IsKeyboardEnabled());
   // Toggle tablet mode off.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  TabletModeControllerTestApi().LeaveTabletMode(false);
   ASSERT_FALSE(keyboard::IsKeyboardEnabled());
 }
 
 // Tests that keyboard gets suppressed in tablet mode.
-TEST_F(VirtualKeyboardControllerAutoTest, SuppressedInMaximizedMode) {
+TEST_F(VirtualKeyboardControllerAutoTest, SuppressedInTabletMode) {
   std::vector<ui::TouchscreenDevice> screens;
   screens.push_back(
       ui::TouchscreenDevice(1, ui::InputDeviceType::INPUT_DEVICE_INTERNAL,
@@ -380,7 +375,7 @@
       2, ui::InputDeviceType::INPUT_DEVICE_EXTERNAL, "Keyboard"));
   ws::InputDeviceClientTestApi().SetKeyboardDevices(keyboard_devices);
   // Toggle tablet mode on.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  TabletModeControllerTestApi().EnterTabletMode();
   ASSERT_FALSE(keyboard::IsKeyboardEnabled());
   ASSERT_TRUE(notified());
   ASSERT_TRUE(IsVirtualKeyboardSuppressed());
@@ -405,7 +400,7 @@
   ASSERT_TRUE(notified());
   ASSERT_FALSE(IsVirtualKeyboardSuppressed());
   // Toggle tablet mode oFF.
-  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false);
+  TabletModeControllerTestApi().LeaveTabletMode(false);
   ASSERT_FALSE(keyboard::IsKeyboardEnabled());
 }
 
diff --git a/ash/metrics/demo_session_metrics_recorder.cc b/ash/metrics/demo_session_metrics_recorder.cc
index 49c11e1..fddc1e0 100644
--- a/ash/metrics/demo_session_metrics_recorder.cc
+++ b/ash/metrics/demo_session_metrics_recorder.cc
@@ -9,6 +9,7 @@
 
 #include "ash/public/cpp/app_types.h"
 #include "ash/public/cpp/window_properties.h"
+#include "ash/shelf/shelf_window_watcher.h"
 #include "ash/shell.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/time/time.h"
@@ -17,6 +18,7 @@
 #include "ui/aura/client/aura_constants.h"
 #include "ui/aura/client/window_types.h"
 #include "ui/aura/window.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/base/user_activity/user_activity_detector.h"
 #include "ui/wm/public/activation_client.h"
 
@@ -104,10 +106,18 @@
   if (app_id == extension_misc::kChromeAppId)
     return DemoModeApp::kBrowser;
 
-  // If the window is the "browser" type, having an app ID other than
-  // kChromeAppId indicates a hosted/bookmark app.
+  auto is_default = [](const std::string& app_id) {
+    if (!features::IsUsingWindowService())
+      return app_id.empty();
+
+    return base::StartsWith(app_id, ShelfWindowWatcher::kDefaultShelfIdPrefix,
+                            base::CompareCase::SENSITIVE);
+  };
+
+  // If the window is the "browser" type, having an app ID other than the
+  // default indicates a hosted/bookmark app.
   if (app_type == ash::AppType::CHROME_APP ||
-      (app_type == ash::AppType::BROWSER && app_id.size())) {
+      (app_type == ash::AppType::BROWSER && !is_default(app_id))) {
     return GetAppFromAppId(app_id);
   }
 
diff --git a/ash/shelf/overflow_bubble_view.cc b/ash/shelf/overflow_bubble_view.cc
index 9eb7623..cd49e1f 100644
--- a/ash/shelf/overflow_bubble_view.cc
+++ b/ash/shelf/overflow_bubble_view.cc
@@ -84,6 +84,17 @@
   AddChildView(shelf_view_);
 }
 
+void OverflowBubbleView::ProcessGestureEvent(const ui::GestureEvent& event) {
+  if (event.type() != ui::ET_GESTURE_SCROLL_UPDATE)
+    return;
+
+  if (shelf_->IsHorizontalAlignment())
+    ScrollByXOffset(static_cast<int>(-event.details().scroll_x()));
+  else
+    ScrollByYOffset(static_cast<int>(-event.details().scroll_y()));
+  Layout();
+}
+
 void OverflowBubbleView::ScrollByXOffset(int x_offset) {
   const gfx::Rect visible_bounds(GetContentsBounds());
   const gfx::Size contents_size(shelf_view_->GetPreferredSize());
@@ -158,8 +169,10 @@
 }
 
 void OverflowBubbleView::OnScrollEvent(ui::ScrollEvent* event) {
-  ScrollByXOffset(-event->x_offset());
-  ScrollByYOffset(-event->y_offset());
+  if (shelf_->IsHorizontalAlignment())
+    ScrollByXOffset(static_cast<int>(-event->x_offset()));
+  else
+    ScrollByYOffset(static_cast<int>(-event->y_offset()));
   Layout();
   event->SetHandled();
 }
diff --git a/ash/shelf/overflow_bubble_view.h b/ash/shelf/overflow_bubble_view.h
index 7072637..131f2a6 100644
--- a/ash/shelf/overflow_bubble_view.h
+++ b/ash/shelf/overflow_bubble_view.h
@@ -27,6 +27,9 @@
   // ShelfView containing the overflow items.
   void InitOverflowBubble(views::View* anchor, ShelfView* shelf_view);
 
+  // Scrolls the bubble contents if it is a scroll update event.
+  void ProcessGestureEvent(const ui::GestureEvent& event);
+
   // views::BubbleDialogDelegateView:
   int GetDialogButtons() const override;
   gfx::Rect GetBubbleBounds() override;
@@ -40,13 +43,13 @@
   void ScrollByXOffset(int x_offset);
   void ScrollByYOffset(int y_offset);
 
-  // views::View overrides:
+  // views::View:
   gfx::Size CalculatePreferredSize() const override;
   void Layout() override;
   void ChildPreferredSizeChanged(views::View* child) override;
   bool OnMouseWheel(const ui::MouseWheelEvent& event) override;
 
-  // ui::EventHandler overrides:
+  // ui::EventHandler:
   void OnScrollEvent(ui::ScrollEvent* event) override;
 
   // ShelfBackgroundAnimatorObserver:
diff --git a/ash/shelf/shelf_view.cc b/ash/shelf/shelf_view.cc
index 0c0509d..5c910c4 100644
--- a/ash/shelf/shelf_view.cc
+++ b/ash/shelf/shelf_view.cc
@@ -1790,6 +1790,15 @@
 }
 
 void ShelfView::OnGestureEvent(ui::GestureEvent* event) {
+  // Do not forward events to |shelf_| (which forwards events to the shelf
+  // layout manager) as we do not want gestures on the overflow to open the app
+  // list for example.
+  if (is_overflow_mode()) {
+    main_shelf_->overflow_bubble()->bubble_view()->ProcessGestureEvent(*event);
+    event->StopPropagation();
+    return;
+  }
+
   // Convert the event location from current view to screen, since swiping up on
   // the shelf can open the fullscreen app list. Updating the bounds of the app
   // list during dragging is based on screen coordinate space.
diff --git a/ash/shelf/shelf_window_watcher.cc b/ash/shelf/shelf_window_watcher.cc
index efaa3a29..141f74ff 100644
--- a/ash/shelf/shelf_window_watcher.cc
+++ b/ash/shelf/shelf_window_watcher.cc
@@ -43,11 +43,11 @@
 // Mash sets and returns an initial default shelf id for unidentified windows.
 // TODO(msw): Extend this Mash behavior to all Ash configs.
 ShelfID GetShelfID(aura::Window* window) {
-  if ((features::IsMultiProcessMash() || features::IsSingleProcessMash()) &&
-      !window->GetProperty(kShelfIDKey) &&
+  if (features::IsUsingWindowService() && !window->GetProperty(kShelfIDKey) &&
       !wm::GetWindowState(window)->ignored_by_shelf()) {
     static int id = 0;
-    const ash::ShelfID shelf_id("ShelfWindowWatcher" + std::to_string(id++));
+    const ash::ShelfID shelf_id(ShelfWindowWatcher::kDefaultShelfIdPrefix +
+                                std::to_string(id++));
     window->SetProperty(kShelfIDKey, new std::string(shelf_id.Serialize()));
     return shelf_id;
   }
@@ -90,6 +90,9 @@
 ShelfWindowWatcher::ContainerWindowObserver::~ContainerWindowObserver() =
     default;
 
+// static
+const char ShelfWindowWatcher::kDefaultShelfIdPrefix[] = "ShelfWindowWatcher";
+
 void ShelfWindowWatcher::ContainerWindowObserver::OnWindowHierarchyChanged(
     const HierarchyChangeParams& params) {
   if (!params.old_parent && params.new_parent &&
diff --git a/ash/shelf/shelf_window_watcher.h b/ash/shelf/shelf_window_watcher.h
index c125bc0..7761361 100644
--- a/ash/shelf/shelf_window_watcher.h
+++ b/ash/shelf/shelf_window_watcher.h
@@ -29,6 +29,8 @@
   explicit ShelfWindowWatcher(ShelfModel* model);
   ~ShelfWindowWatcher() override;
 
+  static const char kDefaultShelfIdPrefix[];
+
  private:
   // Observes for windows being added to a root window's default container.
   class ContainerWindowObserver : public aura::WindowObserver {
diff --git a/ash/shell.cc b/ash/shell.cc
index a2c8d34..0c348fc8 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -626,6 +626,11 @@
     observer.OnOverviewModeEnded();
 }
 
+void Shell::NotifyOverviewModeEndingAnimationComplete() {
+  for (auto& observer : shell_observers_)
+    observer.OnOverviewModeEndingAnimationComplete();
+}
+
 void Shell::NotifySplitViewModeStarting() {
   for (auto& observer : shell_observers_)
     observer.OnSplitViewModeStarting();
diff --git a/ash/shell.h b/ash/shell.h
index 0df8751..58dd502 100644
--- a/ash/shell.h
+++ b/ash/shell.h
@@ -625,6 +625,9 @@
   // Notifies observers that overview mode has ended.
   void NotifyOverviewModeEnded();
 
+  // Notifies observers that the end overivew mode animation has completed.
+  void NotifyOverviewModeEndingAnimationComplete();
+
   // Notifies observers that split view mode is about to be started (before the
   // window gets snapped and activated).
   void NotifySplitViewModeStarting();
diff --git a/ash/shell_observer.h b/ash/shell_observer.h
index 5cb9ac0..2c083af 100644
--- a/ash/shell_observer.h
+++ b/ash/shell_observer.h
@@ -52,7 +52,11 @@
   // Called after overview mode has ended.
   virtual void OnOverviewModeEnded() {}
 
-  // Called when the split view mode is about to be started (before the window
+  // Called after the animations that happen when overview mode is ended are
+  // complete.
+  virtual void OnOverviewModeEndingAnimationComplete() {}
+
+  // Called when the split view mode is about to be started before the window
   // gets snapped and activated).
   virtual void OnSplitViewModeStarting() {}
 
diff --git a/ash/system/overview/overview_button_tray.cc b/ash/system/overview/overview_button_tray.cc
index 9efb6d87..2a86718d 100644
--- a/ash/system/overview/overview_button_tray.cc
+++ b/ash/system/overview/overview_button_tray.cc
@@ -167,7 +167,9 @@
   // not change during transient times in which CanSelect is false. Such as when
   // a modal dialog is present.
   SessionController* session_controller = Shell::Get()->session_controller();
-  SetVisible(Shell::Get()->tablet_mode_controller()->AreEventsBlocked() &&
+  SetVisible(Shell::Get()
+                 ->tablet_mode_controller()
+                 ->AreInternalInputDeviceEventsBlocked() &&
              session_controller->GetSessionState() ==
                  session_manager::SessionState::ACTIVE &&
              !session_controller->IsRunningInAppMode());
diff --git a/ash/system/overview/overview_button_tray_unittest.cc b/ash/system/overview/overview_button_tray_unittest.cc
index 77ee5b27..d3e19b96 100644
--- a/ash/system/overview/overview_button_tray_unittest.cc
+++ b/ash/system/overview/overview_button_tray_unittest.cc
@@ -19,6 +19,7 @@
 #include "ash/wm/overview/window_selector_controller.h"
 #include "ash/wm/splitview/split_view_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
 #include "base/command_line.h"
@@ -84,17 +85,6 @@
     base::RunLoop().RunUntilIdle();
   }
 
-  // Enters or exits tablet mode. Use these instead of
-  // EnableTabletModeWindowManager as tray visibilty depends on the event
-  // blocker instead of the actual tablet mode.
-  void EnterTabletMode() {
-    Shell::Get()->tablet_mode_controller()->AttemptEnterTabletMode();
-  }
-  void LeaveTabletMode(bool called_by_device_update) {
-    Shell::Get()->tablet_mode_controller()->AttemptLeaveTabletMode(
-        called_by_device_update);
-  }
-
   void NotifySessionStateChanged() {
     GetTray()->OnSessionStateChanged(
         Shell::Get()->session_controller()->GetSessionState());
@@ -119,10 +109,10 @@
 // By default the system should not have TabletMode enabled.
 TEST_F(OverviewButtonTrayTest, TabletModeObserverOnTabletModeToggled) {
   ASSERT_FALSE(GetTray()->visible());
-  EnterTabletMode();
+  TabletModeControllerTestApi().EnterTabletMode();
   EXPECT_TRUE(GetTray()->visible());
 
-  LeaveTabletMode(false);
+  TabletModeControllerTestApi().LeaveTabletMode(false);
   EXPECT_FALSE(GetTray()->visible());
 }
 
@@ -208,7 +198,7 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(GetTray()->visible());
   EXPECT_FALSE(GetSecondaryTray()->visible());
-  EnterTabletMode();
+  TabletModeControllerTestApi().EnterTabletMode();
   base::RunLoop().RunUntilIdle();
   // DisplayConfigurationObserver enables mirror mode when tablet mode is
   // enabled. Disable mirror mode to test tablet mode with multiple displays.
@@ -224,7 +214,7 @@
 // so disabling mirror mode after enabling tablet mode does not work.
 // https://crbug.com/798857.
 TEST_F(OverviewButtonTrayTest, DISABLED_SecondaryTrayCreatedVisible) {
-  EnterTabletMode();
+  TabletModeControllerTestApi().EnterTabletMode();
   UpdateDisplay("400x400,200x200");
   base::RunLoop().RunUntilIdle();
   EXPECT_TRUE(GetSecondaryTray()->visible());
@@ -233,7 +223,7 @@
 // Tests that the tray loses visibility when a user logs out, and that it
 // regains visibility when a user logs back in.
 TEST_F(OverviewButtonTrayTest, VisibilityChangesForLoginStatus) {
-  EnterTabletMode();
+  TabletModeControllerTestApi().EnterTabletMode();
   ClearLogin();
   Shell::Get()->UpdateAfterLoginStatusChange(LoginStatus::NOT_LOGGED_IN);
   EXPECT_FALSE(GetTray()->visible());
@@ -269,7 +259,7 @@
 
 // Test that a hide animation can complete.
 TEST_F(OverviewButtonTrayTest, HideAnimationAlwaysCompletes) {
-  EnterTabletMode();
+  TabletModeControllerTestApi().EnterTabletMode();
   EXPECT_TRUE(GetTray()->visible());
   GetTray()->SetVisible(false);
   EXPECT_FALSE(GetTray()->visible());
@@ -278,7 +268,7 @@
 // Test that when a hide animation is aborted via deletion, the
 // OverviewButton is still hidden.
 TEST_F(OverviewButtonTrayTest, HideAnimationAlwaysCompletesOnDelete) {
-  EnterTabletMode();
+  TabletModeControllerTestApi().EnterTabletMode();
 
   // Long duration for hide animation, to allow it to be interrupted.
   std::unique_ptr<ui::ScopedAnimationDurationScaleMode> hide_duration(
@@ -310,9 +300,9 @@
   ParentWindowInPrimaryRootWindow(window.get());
 
   ASSERT_TRUE(Shell::IsSystemModalWindowOpen());
-  EnterTabletMode();
+  TabletModeControllerTestApi().EnterTabletMode();
   EXPECT_TRUE(GetTray()->visible());
-  LeaveTabletMode(false);
+  TabletModeControllerTestApi().LeaveTabletMode(false);
   EXPECT_FALSE(GetTray()->visible());
 }
 
@@ -339,7 +329,7 @@
 // Verify that quick switch works properly when in split view mode.
 TEST_F(OverviewButtonTrayTest, SplitviewModeQuickSwitch) {
   // Splitview is only available in tablet mode.
-  EnterTabletMode();
+  TabletModeControllerTestApi().EnterTabletMode();
 
   std::unique_ptr<aura::Window> window1 = CreateTestWindow();
   std::unique_ptr<aura::Window> window2 = CreateTestWindow();
@@ -374,10 +364,10 @@
 // Tests that the tray remains visible when leaving tablet mode due to external
 // mouse being connected.
 TEST_F(OverviewButtonTrayTest, LeaveTabletModeBecauseExternalMouse) {
-  EnterTabletMode();
+  TabletModeControllerTestApi().EnterTabletMode();
   ASSERT_TRUE(GetTray()->visible());
 
-  LeaveTabletMode(true);
+  TabletModeControllerTestApi().LeaveTabletMode(true);
   EXPECT_TRUE(GetTray()->visible());
 }
 
diff --git a/ash/system/unified/notification_hidden_view.cc b/ash/system/unified/notification_hidden_view.cc
index d27cb53..9b8970a 100644
--- a/ash/system/unified/notification_hidden_view.cc
+++ b/ash/system/unified/notification_hidden_view.cc
@@ -32,12 +32,6 @@
   label->SetLineHeight(kUnifiedNotificationHiddenLineHeight);
   label->SetBorder(views::CreateEmptyBorder(kUnifiedNotificationHiddenPadding));
 
-  auto* clear_all_button = new RoundedLabelButton(
-      this,
-      l10n_util::GetStringUTF16(IDS_ASH_MESSAGE_CENTER_LOCKSCREEN_CHANGE));
-  clear_all_button->SetTooltipText(l10n_util::GetStringUTF16(
-      IDS_ASH_MESSAGE_CENTER_LOCKSCREEN_CHANGE_TOOLTIP));
-
   auto* container = new views::View;
   container->SetBackground(views::CreateBackgroundFromPainter(
       views::Painter::CreateSolidRoundRectPainter(kUnifiedMenuButtonColor,
@@ -48,8 +42,15 @@
 
   container->AddChildView(label);
   layout->SetFlexForView(label, 1);
+
   if (lock_screen_notification_enabled) {
-    container->AddChildView(clear_all_button);
+    auto* change_button = new RoundedLabelButton(
+        this,
+        l10n_util::GetStringUTF16(IDS_ASH_MESSAGE_CENTER_LOCKSCREEN_CHANGE));
+    change_button->SetTooltipText(l10n_util::GetStringUTF16(
+        IDS_ASH_MESSAGE_CENTER_LOCKSCREEN_CHANGE_TOOLTIP));
+
+    container->AddChildView(change_button);
   }
 
   SetBorder(
diff --git a/ash/wm/overview/overview_utils.cc b/ash/wm/overview/overview_utils.cc
index 08af7352..94224e9 100644
--- a/ash/wm/overview/overview_utils.cc
+++ b/ash/wm/overview/overview_utils.cc
@@ -162,10 +162,8 @@
   // window selector controller which has longer lifetime so that animations can
   // continue even after the overview mode is shut down.
   views::Widget* widget_ptr = widget.get();
-  std::unique_ptr<CleanupAnimationObserver> observer(
-      new CleanupAnimationObserver(std::move(widget)));
+  auto observer = std::make_unique<CleanupAnimationObserver>(std::move(widget));
   animation_settings.AddObserver(observer.get());
-
   controller->AddDelayedAnimationObserver(std::move(observer));
   widget_ptr->SetOpacity(0.f);
   if (slide) {
diff --git a/ash/wm/overview/scoped_overview_animation_settings.cc b/ash/wm/overview/scoped_overview_animation_settings.cc
index 47d986a..26e7e99 100644
--- a/ash/wm/overview/scoped_overview_animation_settings.cc
+++ b/ash/wm/overview/scoped_overview_animation_settings.cc
@@ -33,6 +33,7 @@
 // The time duration for widgets to fade out.
 constexpr int kFadeOutMs = 100;
 
+constexpr int kFromHomeLauncherDelayMs = 250;
 constexpr int kHomeLauncherTransitionMs = 250;
 
 base::TimeDelta GetAnimationDuration(OverviewAnimationType animation_type) {
@@ -179,6 +180,14 @@
           ui::LayerAnimator::ENQUEUE_NEW_ANIMATION);
       break;
     case OVERVIEW_ANIMATION_ENTER_FROM_HOME_LAUNCHER:
+      animation_settings_->SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN);
+      animation_settings_->SetPreemptionStrategy(
+          ui::LayerAnimator::ENQUEUE_NEW_ANIMATION);
+      window->layer()->GetAnimator()->SchedulePauseForProperties(
+          base::TimeDelta::FromMilliseconds(kFromHomeLauncherDelayMs),
+          ui::LayerAnimationElement::OPACITY |
+              ui::LayerAnimationElement::TRANSFORM);
+      break;
     case OVERVIEW_ANIMATION_EXIT_TO_HOME_LAUNCHER:
       animation_settings_->SetTweenType(gfx::Tween::FAST_OUT_SLOW_IN);
       animation_settings_->SetPreemptionStrategy(
diff --git a/ash/wm/overview/window_selector.cc b/ash/wm/overview/window_selector.cc
index ebf2df7..3955e25 100644
--- a/ash/wm/overview/window_selector.cc
+++ b/ash/wm/overview/window_selector.cc
@@ -929,14 +929,21 @@
 void WindowSelector::OnSplitViewStateChanged(
     SplitViewController::State previous_state,
     SplitViewController::State state) {
-  if (state != SplitViewController::NO_SNAP) {
-    // Do not restore focus if a window was just snapped and activated.
+  const bool unsnappable_window_activated =
+      state == SplitViewController::NO_SNAP &&
+      Shell::Get()->split_view_controller()->end_reason() ==
+          SplitViewController::EndReason::kUnsnappableWindowActivated;
+
+  if (state != SplitViewController::NO_SNAP || unsnappable_window_activated) {
+    // Do not restore focus if a window was just snapped and activated or
+    // splitview mode is ended by activating an unsnappable window.
     ResetFocusRestoreWindow(false);
   }
 
-  if (state == SplitViewController::BOTH_SNAPPED) {
-    // If two windows were snapped to both sides of the screen, end overview
-    // mode.
+  if (state == SplitViewController::BOTH_SNAPPED ||
+      unsnappable_window_activated) {
+    // If two windows were snapped to both sides of the screen or an unsnappable
+    // window was just activated, end overview mode.
     CancelSelection();
   } else {
     // Otherwise adjust the overview window grid bounds if overview mode is
diff --git a/ash/wm/overview/window_selector_controller.cc b/ash/wm/overview/window_selector_controller.cc
index 5dcc4ae..7289d4c0 100644
--- a/ash/wm/overview/window_selector_controller.cc
+++ b/ash/wm/overview/window_selector_controller.cc
@@ -23,8 +23,10 @@
 #include "ash/wm/splitview/split_view_controller.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/window_util.h"
+#include "base/containers/unique_ptr_adapters.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
+#include "base/stl_util.h"
 #include "ui/aura/client/aura_constants.h"
 #include "ui/gfx/animation/animation_delegate.h"
 #include "ui/gfx/animation/slide_animation.h"
@@ -193,16 +195,20 @@
 
     WindowSelector* window_selector =
         Shell::Get()->window_selector_controller()->window_selector();
-    DCHECK(window_selector);
-
     for (aura::Window* root : Shell::Get()->GetAllRootWindows()) {
-      if (window_selector->ShouldAnimateWallpaper(root)) {
-        root->AddObserver(this);
-        roots_to_animate_.push_back(root);
-      } else {
-        animation_.Reset(should_blur ? 1.0 : 0.0);
-        ApplyBlur(root, value);
+      // No need to animate the blur on exiting as this should only be called
+      // after overview animations are finished.
+      if (should_blur) {
+        DCHECK(window_selector);
+        if (window_selector->ShouldAnimateWallpaper(root)) {
+          root->AddObserver(this);
+          roots_to_animate_.push_back(root);
+          continue;
+        }
       }
+
+      animation_.Reset(should_blur ? 1.0 : 0.0);
+      ApplyBlur(root, value);
     }
 
     // Run the animation if one of the roots needs to be animated.
@@ -301,7 +307,12 @@
     if (!CanSelect())
       return false;
 
-    window_selector_.reset(new WindowSelector(this));
+    // Clear any animations that may be running from last overview end.
+    for (const auto& animation : delayed_animations_)
+      animation->Shutdown();
+    delayed_animations_.clear();
+
+    window_selector_ = std::make_unique<WindowSelector>(this);
     window_selector_->set_use_slide_animation(should_slide_overview);
     Shell::Get()->NotifyOverviewModeStarting();
     window_selector_->Init(windows, hide_windows);
@@ -445,13 +456,13 @@
 void WindowSelectorController::OnSelectionEnded() {
   if (is_shutting_down_)
     return;
-
-  if (IsBlurAllowed())
-    overview_blur_controller_->Unblur();
   is_shutting_down_ = true;
   Shell::Get()->NotifyOverviewModeEnding();
   auto* window_selector = window_selector_.release();
   window_selector->Shutdown();
+  // There may be no delayed animations in tests, so unblur right away.
+  if (delayed_animations_.empty() && IsBlurAllowed())
+    overview_blur_controller_->Unblur();
   // Don't delete |window_selector_| yet since the stack is still using it.
   base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, window_selector);
   last_selection_time_ = base::Time::Now();
@@ -467,21 +478,17 @@
 
 void WindowSelectorController::RemoveAndDestroyAnimationObserver(
     DelayedAnimationObserver* animation_observer) {
-  class IsEqual {
-   public:
-    explicit IsEqual(DelayedAnimationObserver* animation_observer)
-        : animation_observer_(animation_observer) {}
-    bool operator()(const std::unique_ptr<DelayedAnimationObserver>& other) {
-      return (other.get() == animation_observer_);
-    }
+  const bool previous_empty = delayed_animations_.empty();
+  base::EraseIf(delayed_animations_,
+                base::MatchesUniquePtr(animation_observer));
 
-   private:
-    const DelayedAnimationObserver* animation_observer_;
-  };
-  delayed_animations_.erase(
-      std::remove_if(delayed_animations_.begin(), delayed_animations_.end(),
-                     IsEqual(animation_observer)),
-      delayed_animations_.end());
+  // If something has been removed and its the last observer, unblur the
+  // wallpaper and let observers know.
+  if (!previous_empty && delayed_animations_.empty()) {
+    if (IsBlurAllowed())
+      overview_blur_controller_->Unblur();
+    Shell::Get()->NotifyOverviewModeEndingAnimationComplete();
+  }
 }
 
 // static
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc
index 566ce9f..ac8c579 100644
--- a/ash/wm/splitview/split_view_controller.cc
+++ b/ash/wm/splitview/split_view_controller.cc
@@ -695,7 +695,7 @@
   // mode and show the cannot snap toast.
   if (!CanSnap(gained_active)) {
     if (wm::GetWindowState(gained_active)->IsUserPositionable()) {
-      EndSplitView();
+      EndSplitView(EndReason::kUnsnappableWindowActivated);
       ShowAppCannotSnapToast();
     }
     return;
diff --git a/ash/wm/splitview/split_view_controller.h b/ash/wm/splitview/split_view_controller.h
index 1f8c26bb6..94325b9 100644
--- a/ash/wm/splitview/split_view_controller.h
+++ b/ash/wm/splitview/split_view_controller.h
@@ -58,10 +58,12 @@
   enum SnapPosition { NONE, LEFT, RIGHT };
 
   // Why splitview was ended. For now, all reasons will be kNormal except when
-  // the home launcher button is pressed.
+  // the home launcher button is pressed or an unsnappable window just got
+  // activated.
   enum class EndReason {
     kNormal = 0,
     kHomeLauncherPressed,
+    kUnsnappableWindowActivated,
   };
 
   class Observer {
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc
index d11934e3..563eaaef 100644
--- a/ash/wm/splitview/split_view_controller_unittest.cc
+++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -1596,6 +1596,24 @@
   EXPECT_FALSE(wm::GetWindowState(window2.get())->IsMaximized());
 }
 
+// Test that if overview and splitview are both active at the same time,
+// activiate an unsnappable window should end both overview and splitview mode.
+TEST_F(SplitViewControllerTest, ActivateNonSnappableWindow) {
+  const gfx::Rect bounds(0, 0, 400, 400);
+  std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
+  std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
+  std::unique_ptr<aura::Window> window3(CreateNonSnappableWindow(bounds));
+
+  split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
+  ToggleOverview();
+  EXPECT_TRUE(split_view_controller()->IsSplitViewModeActive());
+  EXPECT_TRUE(Shell::Get()->window_selector_controller()->IsSelecting());
+
+  wm::ActivateWindow(window3.get());
+  EXPECT_FALSE(split_view_controller()->IsSplitViewModeActive());
+  EXPECT_FALSE(Shell::Get()->window_selector_controller()->IsSelecting());
+}
+
 // Test the tab-dragging related functionalities in tablet mode. Tab(s) can be
 // dragged out of a window and then put in split view mode or merge into another
 // window.
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.cc b/ash/wm/tablet_mode/tablet_mode_controller.cc
index ea3fdc8..805cdbb 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller.cc
@@ -455,7 +455,7 @@
   return true;
 }
 
-bool TabletModeController::AreEventsBlocked() const {
+bool TabletModeController::AreInternalInputDeviceEventsBlocked() const {
   return !!event_blocker_.get();
 }
 
@@ -595,10 +595,4 @@
   return elapsed_time >= kUnstableLidAngleDuration;
 }
 
-void TabletModeController::SetTickClockForTest(
-    const base::TickClock* tick_clock) {
-  DCHECK(tick_clock_);
-  tick_clock_ = tick_clock;
-}
-
 }  // namespace ash
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.h b/ash/wm/tablet_mode/tablet_mode_controller.h
index a8434ee..c7cf25be 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller.h
+++ b/ash/wm/tablet_mode/tablet_mode_controller.h
@@ -46,10 +46,8 @@
 namespace ash {
 
 class ScopedDisableInternalMouseAndKeyboard;
-class TabletModeControllerTest;
 class TabletModeObserver;
 class TabletModeWindowManager;
-class TabletModeWindowManagerTest;
 
 // TabletModeController listens to accelerometer events and automatically
 // enters and exits tablet mode when the lid is opened beyond the triggering
@@ -116,7 +114,7 @@
   bool TriggerRecordLidAngleTimerForTesting() WARN_UNUSED_RESULT;
 
   // Whether the events from the internal mouse/keyboard are blocked.
-  bool AreEventsBlocked() const;
+  bool AreInternalInputDeviceEventsBlocked() const;
 
   // ShellObserver:
   void OnShellInitialized() override;
@@ -144,11 +142,7 @@
   void OnDeviceListsComplete() override;
 
  private:
-  friend class OverviewButtonTrayTest;
-  friend class TabletModeControllerTest;
-  friend class TabletModeWindowManagerTest;
-  friend class MultiUserWindowManagerChromeOSTest;
-  friend class VirtualKeyboardControllerTest;
+  friend class TabletModeControllerTestApi;
 
   // Used for recording metrics for intervals of time spent in
   // and out of TabletMode.
@@ -157,12 +151,6 @@
     TABLET_MODE_INTERVAL_ACTIVE
   };
 
-  // Set the TickClock. This is only to be used by tests that need to
-  // artificially and deterministically control the current time.
-  // This does not take the ownership of the tick_clock. |tick_clock| must
-  // outlive the TabletModeController instance.
-  void SetTickClockForTest(const base::TickClock* tick_clock);
-
   // Detect hinge rotation from base and lid accelerometers and automatically
   // start / stop tablet mode.
   void HandleHingeRotation(
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_test_api.cc b/ash/wm/tablet_mode/tablet_mode_controller_test_api.cc
new file mode 100644
index 0000000..f06665a
--- /dev/null
+++ b/ash/wm/tablet_mode/tablet_mode_controller_test_api.cc
@@ -0,0 +1,25 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
+
+#include "ash/shell.h"
+
+namespace ash {
+
+TabletModeControllerTestApi::TabletModeControllerTestApi()
+    : tablet_mode_controller_(Shell::Get()->tablet_mode_controller()) {}
+
+TabletModeControllerTestApi::~TabletModeControllerTestApi() = default;
+
+void TabletModeControllerTestApi::EnterTabletMode() {
+  tablet_mode_controller_->AttemptEnterTabletMode();
+}
+
+void TabletModeControllerTestApi::LeaveTabletMode(
+    bool called_by_device_update) {
+  tablet_mode_controller_->AttemptLeaveTabletMode(called_by_device_update);
+}
+
+}  // namespace ash
\ No newline at end of file
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_test_api.h b/ash/wm/tablet_mode/tablet_mode_controller_test_api.h
new file mode 100644
index 0000000..83897dbe
--- /dev/null
+++ b/ash/wm/tablet_mode/tablet_mode_controller_test_api.h
@@ -0,0 +1,69 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_WM_TABLET_MODE_TABLET_MODE_CONTROLLER_TEST_API_H_
+#define ASH_WM_TABLET_MODE_TABLET_MODE_CONTROLLER_TEST_API_H_
+
+#include <memory>
+
+#include "ash/wm/tablet_mode/scoped_disable_internal_mouse_and_keyboard.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "base/macros.h"
+
+namespace ash {
+
+class ScopedDisableInternalMouseAndKeyboard;
+class TabletModeController;
+class TabletModeWindowManager;
+
+// Use the api in this class to test TabletModeController.
+class TabletModeControllerTestApi {
+ public:
+  TabletModeControllerTestApi();
+  ~TabletModeControllerTestApi();
+
+  // Enters or exits tablet mode. Use these instead when stuff such as tray
+  // visibilty depends on the event blocker instead of the actual tablet mode.
+  void EnterTabletMode();
+  void LeaveTabletMode(bool called_by_device_update);
+
+  // Sets the event blocker on the tablet mode controller.
+  void set_event_blocker(
+      std::unique_ptr<ScopedDisableInternalMouseAndKeyboard> blocker) {
+    tablet_mode_controller_->event_blocker_ = std::move(blocker);
+  }
+
+  TabletModeWindowManager* tablet_mode_window_manager() {
+    return tablet_mode_controller_->tablet_mode_window_manager_.get();
+  }
+
+  // Set the TickClock. This is only to be used by tests that need to
+  // artificially and deterministically control the current time.
+  // This does not take the ownership of the tick_clock. |tick_clock| must
+  // outlive the TabletModeController instance.
+  void set_tick_clock(const base::TickClock* tick_clock) {
+    DCHECK(tick_clock);
+    tablet_mode_controller_->tick_clock_ = tick_clock;
+  }
+  const base::TickClock* tick_clock() {
+    return tablet_mode_controller_->tick_clock_;
+  }
+
+  bool CanUseUnstableLidAngle() const {
+    return tablet_mode_controller_->CanUseUnstableLidAngle();
+  }
+
+  TabletModeController::UiMode force_ui_mode() const {
+    return tablet_mode_controller_->force_ui_mode_;
+  }
+
+ private:
+  TabletModeController* tablet_mode_controller_;
+
+  DISALLOW_COPY_AND_ASSIGN(TabletModeControllerTestApi);
+};
+
+}  // namespace ash
+
+#endif  // ASH_WM_TABLET_MODE_TABLET_MODE_CONTROLLER_TEST_API_H_
\ No newline at end of file
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
index 0ce5289..ac464f35 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
@@ -13,6 +13,7 @@
 #include "ash/shell.h"
 #include "ash/test/ash_test_base.h"
 #include "ash/wm/overview/window_selector_controller.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
 #include "base/command_line.h"
 #include "base/run_loop.h"
 #include "base/test/metrics/histogram_tester.h"
@@ -85,6 +86,8 @@
     // screen rotation tests.
     display::test::DisplayManagerTestApi(Shell::Get()->display_manager())
         .SetFirstDisplayAsInternalDisplay();
+
+    test_api_ = std::make_unique<TabletModeControllerTestApi>();
   }
 
   void TearDown() override {
@@ -124,7 +127,7 @@
   // null value initial value.
   void AttachTickClockForTest() {
     test_tick_clock_.Advance(base::TimeDelta::FromSeconds(1));
-    tablet_mode_controller()->SetTickClockForTest(&test_tick_clock_);
+    test_api_->set_tick_clock(&test_tick_clock_);
   }
 
   void AdvanceTickClock(const base::TimeDelta& delta) {
@@ -151,37 +154,37 @@
   void OpenLid() {
     tablet_mode_controller()->LidEventReceived(
         chromeos::PowerManagerClient::LidState::OPEN,
-        tablet_mode_controller()->tick_clock_->NowTicks());
+        test_api_->tick_clock()->NowTicks());
   }
 
   void CloseLid() {
     tablet_mode_controller()->LidEventReceived(
         chromeos::PowerManagerClient::LidState::CLOSED,
-        tablet_mode_controller()->tick_clock_->NowTicks());
+        test_api_->tick_clock()->NowTicks());
   }
 
-  bool CanUseUnstableLidAngle() {
-    return tablet_mode_controller()->CanUseUnstableLidAngle();
-  }
+  bool CanUseUnstableLidAngle() { return test_api_->CanUseUnstableLidAngle(); }
 
   void SetTabletMode(bool on) {
     tablet_mode_controller()->TabletModeEventReceived(
         on ? chromeos::PowerManagerClient::TabletMode::ON
            : chromeos::PowerManagerClient::TabletMode::OFF,
-        tablet_mode_controller()->tick_clock_->NowTicks());
+        test_api_->tick_clock()->NowTicks());
   }
 
   bool AreEventsBlocked() {
-    return tablet_mode_controller()->AreEventsBlocked();
+    return tablet_mode_controller()->AreInternalInputDeviceEventsBlocked();
   }
 
-  TabletModeController::UiMode forced_ui_mode() {
-    return tablet_mode_controller()->force_ui_mode_;
+  TabletModeController::UiMode forced_ui_mode() const {
+    return test_api_->force_ui_mode();
   }
 
   base::UserActionTester* user_action_tester() { return &user_action_tester_; }
 
  private:
+  std::unique_ptr<TabletModeControllerTestApi> test_api_;
+
   base::SimpleTestTickClock test_tick_clock_;
 
   // Tracks user action counts.
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
index 6b45dcc..307cd53 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
@@ -22,6 +22,7 @@
 #include "ash/wm/overview/window_selector_controller.h"
 #include "ash/wm/switchable_windows.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
 #include "ash/wm/window_properties.h"
 #include "ash/wm/window_resizer.h"
 #include "ash/wm/window_state.h"
@@ -123,23 +124,16 @@
 
   // Create the tablet mode window manager.
   TabletModeWindowManager* CreateTabletModeWindowManager() {
-    EXPECT_FALSE(tablet_mode_window_manager());
+    EXPECT_FALSE(TabletModeControllerTestApi().tablet_mode_window_manager());
     Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
-    return tablet_mode_window_manager();
+    return TabletModeControllerTestApi().tablet_mode_window_manager();
   }
 
   // Destroy the tablet mode window manager.
   void DestroyTabletModeWindowManager() {
     Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(
         false);
-    EXPECT_FALSE(tablet_mode_window_manager());
-  }
-
-  // Get the tablet window manager.
-  TabletModeWindowManager* tablet_mode_window_manager() {
-    return Shell::Get()
-        ->tablet_mode_controller()
-        ->tablet_mode_window_manager_.get();
+    EXPECT_FALSE(TabletModeControllerTestApi().tablet_mode_window_manager());
   }
 
   // Resize our desktop.
diff --git a/base/BUILD.gn b/base/BUILD.gn
index 0d50d0f..f474554b 100644
--- a/base/BUILD.gn
+++ b/base/BUILD.gn
@@ -1919,7 +1919,7 @@
 buildflag_header("anchor_functions_buildflags") {
   header = "anchor_functions_buildflags.h"
   header_dir = "base/android/library_loader"
-  _supports_code_ordering = current_cpu == "arm"
+  _supports_code_ordering = current_cpu == "arm" || current_cpu == "arm64"
 
   flags = [
     "USE_LLD=$use_lld",
diff --git a/base/task/post_task_unittest.cc b/base/task/post_task_unittest.cc
index d65fe68..66bdb00 100644
--- a/base/task/post_task_unittest.cc
+++ b/base/task/post_task_unittest.cc
@@ -187,13 +187,8 @@
   }
 }
 
-// Flaky on CrOS (https://crbug.com/879984).
-#if defined(OS_CHROMEOS)
-#define MAYBE_RegisterExecutorTwice DISABLED_RegisterExecutorTwice
-#else
-#define MAYBE_RegisterExecutorTwice RegisterExecutorTwice
-#endif
-TEST_F(PostTaskTestWithExecutor, MAYBE_RegisterExecutorTwice) {
+TEST_F(PostTaskTestWithExecutor, RegisterExecutorTwice) {
+  testing::FLAGS_gtest_death_test_style = "threadsafe";
   EXPECT_DCHECK_DEATH(
       RegisterTaskExecutor(TestTaskTraitsExtension::kExtensionId, &executor_));
 }
diff --git a/chrome/VERSION b/chrome/VERSION
index 52f98b0..1fb51f9 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=71
 MINOR=0
-BUILD=3544
+BUILD=3545
 PATCH=0
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index 3215e0c7..a3d569f 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -387,11 +387,6 @@
             {{ self.supports_vr() }}
             {{ self.extra_web_rendering_activity_definitions() }}
         </activity>
-        <!-- SeparateTaskCustomTabActivity is a wrapper of CustomTabActivity. It provides the
-             general feeling of supporting multi tasks, even for versions that did not fully support
-             it.
-             TODO(arthursonzogni, tedchoc): Enabled this only on Android < 21 after M74.
-        -->
         <activity android:name="org.chromium.chrome.browser.customtabs.SeparateTaskCustomTabActivity"
             android:theme="@style/MainTheme"
             android:exported="false"
@@ -404,23 +399,21 @@
             {{ self.supports_vr() }}
             {{ self.extra_web_rendering_activity_definitions() }}
         </activity>
-        {% if min_sdk_version|int < 21 %}
-          {% for i in range(10) %}
-            <activity android:name="org.chromium.chrome.browser.customtabs.SeparateTaskCustomTabActivity{{ i }}"
-                android:theme="@style/MainTheme"
-                android:icon="@mipmap/app_single_page_icon"
-                android:exported="false"
-                android:launchMode="singleTask"
-                android:persistableMode="persistNever"
-                android:taskAffinity=""
-                {{ self.chrome_activity_common() }}
-                {{ self.supports_video_persistence() }}
-            >
-                {{ self.supports_vr() }}
-                {{ self.extra_web_rendering_activity_definitions() }}
-            </activity>
-          {% endfor %}
-        {% endif %}
+        {% for i in range(10) %}
+        <activity android:name="org.chromium.chrome.browser.customtabs.SeparateTaskCustomTabActivity{{ i }}"
+            android:theme="@style/MainTheme"
+            android:icon="@mipmap/app_single_page_icon"
+            android:exported="false"
+            android:launchMode="singleTask"
+            android:persistableMode="persistNever"
+            android:taskAffinity=""
+            {{ self.chrome_activity_common() }}
+            {{ self.supports_video_persistence() }}
+        >
+            {{ self.supports_vr() }}
+            {{ self.extra_web_rendering_activity_definitions() }}
+        </activity>
+        {% endfor %}
 
         <activity android:name="org.chromium.chrome.browser.incognito.IncognitoDisclosureActivity"
           android:theme="@style/FullscreenTransparentActivityTheme"
diff --git a/chrome/android/java/res/color/light_mode_tint.xml b/chrome/android/java/res/color/light_mode_tint.xml
index 0d503ad..af106cf5 100644
--- a/chrome/android/java/res/color/light_mode_tint.xml
+++ b/chrome/android/java/res/color/light_mode_tint.xml
@@ -9,5 +9,5 @@
     <item android:state_pressed="true" android:color="#80FFFFFF" />
     <item android:state_activated="true" android:color="#80FFFFFF" />
     <item android:state_enabled="false" android:color="#33FFFFFF" />
-    <item android:color="#FFFFFF"/>
+    <item android:color="@color/default_icon_color_white"/>
 </selector>
diff --git a/chrome/android/java/res/drawable-hdpi/chromelogo16.png b/chrome/android/java/res/drawable-hdpi/chromelogo16.png
new file mode 100644
index 0000000..94e727a
--- /dev/null
+++ b/chrome/android/java/res/drawable-hdpi/chromelogo16.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-hdpi/default_favicon_white.png b/chrome/android/java/res/drawable-hdpi/default_favicon_white.png
deleted file mode 100644
index 3aebda9..0000000
--- a/chrome/android/java/res/drawable-hdpi/default_favicon_white.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/chromelogo16.png b/chrome/android/java/res/drawable-mdpi/chromelogo16.png
new file mode 100644
index 0000000..da305f9d
--- /dev/null
+++ b/chrome/android/java/res/drawable-mdpi/chromelogo16.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-mdpi/default_favicon_white.png b/chrome/android/java/res/drawable-mdpi/default_favicon_white.png
deleted file mode 100644
index 32f3789d..0000000
--- a/chrome/android/java/res/drawable-mdpi/default_favicon_white.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/chromelogo16.png b/chrome/android/java/res/drawable-xhdpi/chromelogo16.png
new file mode 100644
index 0000000..ae0ea90
--- /dev/null
+++ b/chrome/android/java/res/drawable-xhdpi/chromelogo16.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xhdpi/default_favicon_white.png b/chrome/android/java/res/drawable-xhdpi/default_favicon_white.png
deleted file mode 100644
index d91cd37..0000000
--- a/chrome/android/java/res/drawable-xhdpi/default_favicon_white.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/chromelogo16.png b/chrome/android/java/res/drawable-xxhdpi/chromelogo16.png
new file mode 100644
index 0000000..dab57ba
--- /dev/null
+++ b/chrome/android/java/res/drawable-xxhdpi/chromelogo16.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxhdpi/default_favicon_white.png b/chrome/android/java/res/drawable-xxhdpi/default_favicon_white.png
deleted file mode 100644
index da2ed4cc..0000000
--- a/chrome/android/java/res/drawable-xxhdpi/default_favicon_white.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/chromelogo16.png b/chrome/android/java/res/drawable-xxxhdpi/chromelogo16.png
new file mode 100644
index 0000000..cd25644
--- /dev/null
+++ b/chrome/android/java/res/drawable-xxxhdpi/chromelogo16.png
Binary files differ
diff --git a/chrome/android/java/res/drawable-xxxhdpi/default_favicon_white.png b/chrome/android/java/res/drawable-xxxhdpi/default_favicon_white.png
deleted file mode 100644
index 2b998f1..0000000
--- a/chrome/android/java/res/drawable-xxxhdpi/default_favicon_white.png
+++ /dev/null
Binary files differ
diff --git a/chrome/android/java/res/xml/autofill_and_payments_preferences.xml b/chrome/android/java/res/xml/autofill_and_payments_preferences.xml
index 07091ff..6a3b326 100644
--- a/chrome/android/java/res/xml/autofill_and_payments_preferences.xml
+++ b/chrome/android/java/res/xml/autofill_and_payments_preferences.xml
@@ -12,7 +12,7 @@
 
     <org.chromium.chrome.browser.preferences.ChromeBasePreference
        android:title="@string/autofill_payment_methods"
-       android:fragment="org.chromium.chrome.browser.preferences.autofill.AutofillCreditCardsFragment"
+       android:fragment="org.chromium.chrome.browser.preferences.autofill.AutofillPaymentMethodsFragment"
        android:key="autofill_payment_methods" />
 
 </PreferenceScreen>
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java b/chrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java
index 9ea442a..7e451ea 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/LaunchIntentDispatcher.java
@@ -300,40 +300,34 @@
             newIntent.setFlags(newIntent.getFlags() | Intent.FLAG_ACTIVITY_NEW_TASK);
         }
 
-        // Handle activity started in a new task.
-        // See https://developer.android.com/guide/components/activities/tasks-and-back-stack
+        // If a CCT intent triggers First Run, then NEW_TASK will be automatically applied.  As
+        // part of that, it will inherit the EXCLUDE_FROM_RECENTS bit from ChromeLauncherActivity,
+        // so explicitly remove it to ensure the CCT does not get lost in recents.
         if ((newIntent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK) != 0
                 || (newIntent.getFlags() & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0) {
-            // If a CCT intent triggers First Run, then NEW_TASK will be automatically applied. As
-            // part of that, it will inherit the EXCLUDE_FROM_RECENTS bit from
-            // ChromeLauncherActivity, so explicitly remove it to ensure the CCT does not get lost
-            // in recents.
             newIntent.setFlags(newIntent.getFlags() & ~Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-
-            // Android will try to find and reuse an existing CCT activity in the background. Use
-            // this flag to always start a new one instead.
+            String uuid = UUID.randomUUID().toString();
             newIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
-
-            // Provide the general feeling of supporting multi tasks in Android version that did not
-            // fully support them. Reuse the least recently used SeparateTaskCustomTabActivity
-            // instance.
-            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
-                String uuid = UUID.randomUUID().toString();
+            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+                // Force a new document L+ to ensure the proper task/stack creation.
+                newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
+                newIntent.setClassName(context, SeparateTaskCustomTabActivity.class.getName());
+            } else {
                 int activityIndex = ActivityAssigner
                                             .instance(ActivityAssigner.ActivityAssignerNamespace
                                                               .SEPARATE_TASK_CCT_NAMESPACE)
                                             .assign(uuid);
                 String className = SeparateTaskCustomTabActivity.class.getName() + activityIndex;
                 newIntent.setClassName(context, className);
-
-                String url = IntentHandler.getUrlFromIntent(newIntent);
-                assert url != null;
-                newIntent.setData(new Uri.Builder()
-                                          .scheme(UrlConstants.CUSTOM_TAB_SCHEME)
-                                          .authority(uuid)
-                                          .query(url)
-                                          .build());
             }
+
+            String url = IntentHandler.getUrlFromIntent(newIntent);
+            assert url != null;
+            newIntent.setData(new Uri.Builder()
+                                      .scheme(UrlConstants.CUSTOM_TAB_SCHEME)
+                                      .authority(uuid)
+                                      .query(url)
+                                      .build());
         }
 
         // If the previous caller was not Chrome, but added EXTRA_IS_OPENED_BY_CHROME for malicious
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/NavigationPopup.java b/chrome/android/java/src/org/chromium/chrome/browser/NavigationPopup.java
index e405c5cd..b4f8e33 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/NavigationPopup.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/NavigationPopup.java
@@ -6,7 +6,6 @@
 
 import android.content.Context;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.graphics.Color;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
@@ -29,6 +28,7 @@
 import org.chromium.base.ThreadUtils;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.favicon.FaviconHelper;
+import org.chromium.chrome.browser.favicon.FaviconHelper.DefaultFaviconHelper;
 import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback;
 import org.chromium.chrome.browser.history.HistoryManagerUtils;
 import org.chromium.chrome.browser.profiles.Profile;
@@ -57,7 +57,7 @@
 
     private final int mFaviconSize;
 
-    private Bitmap mDefaultFavicon;
+    private DefaultFaviconHelper mDefaultFaviconHelper;
 
     /**
      * Loads the favicons asynchronously.
@@ -118,6 +118,7 @@
     public void dismiss() {
         if (mInitialized) mFaviconHelper.destroy();
         mInitialized = false;
+        if (mDefaultFaviconHelper != null) mDefaultFaviconHelper.clearCache();
         super.dismiss();
     }
 
@@ -169,17 +170,14 @@
      * @param pageUrl the page for which the favicon was retrieved.
      * @param favicon the favicon data.
      */
-    private void onFaviconAvailable(String pageUrl, Object favicon) {
+    private void onFaviconAvailable(String pageUrl, Bitmap favicon) {
         if (favicon == null) {
-            if (mDefaultFavicon == null) {
-                mDefaultFavicon = BitmapFactory.decodeResource(
-                        mContext.getResources(), R.drawable.default_favicon);
-            }
-            favicon = mDefaultFavicon;
+            if (mDefaultFaviconHelper == null) mDefaultFaviconHelper = new DefaultFaviconHelper();
+            favicon = mDefaultFaviconHelper.getDefaultFaviconBitmap(mContext, pageUrl, true);
         }
         for (int i = 0; i < mHistory.getEntryCount(); i++) {
             NavigationEntry entry = mHistory.getEntryAtIndex(i);
-            if (TextUtils.equals(pageUrl, entry.getUrl())) entry.updateFavicon((Bitmap) favicon);
+            if (TextUtils.equals(pageUrl, entry.getUrl())) entry.updateFavicon(favicon);
         }
         mAdapter.notifyDataSetChanged();
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetViewBinder.java
index 367ead0..22f8a066 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/AccessorySheetViewBinder.java
@@ -21,7 +21,12 @@
             viewPager.setAdapter(
                     AccessorySheetCoordinator.createTabViewAdapter(model.getTabList(), viewPager));
         } else if (propertyKey == PropertyKey.VISIBLE) {
+            viewPager.bringToFront(); // Ensure toolbars and other containers are overlaid.
             viewPager.setVisibility(model.isVisible() ? View.VISIBLE : View.GONE);
+            if (model.isVisible()
+                    && model.getActiveTabIndex() != AccessorySheetModel.NO_ACTIVE_TAB) {
+                announceOpenedTab(viewPager, model.getTabList().get(model.getActiveTabIndex()));
+            }
         } else if (propertyKey == PropertyKey.HEIGHT) {
             ViewGroup.LayoutParams p = viewPager.getLayoutParams();
             p.height = model.getHeight();
@@ -34,4 +39,9 @@
             assert false : "Every possible property update needs to be handled!";
         }
     }
+
+    static void announceOpenedTab(View announcer, KeyboardAccessoryData.Tab tab) {
+        if (tab.getOpeningAnnouncement() == null) return;
+        announcer.announceForAccessibility(tab.getOpeningAnnouncement());
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java
index 4123c19..e4728ee 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryData.java
@@ -62,6 +62,7 @@
      */
     public final static class Tab {
         private final Drawable mIcon;
+        private final @Nullable String mOpeningAnnouncement;
         private final String mContentDescription;
         private final int mTabLayout;
         private final @AccessoryTabType int mRecordingType;
@@ -85,8 +86,15 @@
 
         public Tab(Drawable icon, String contentDescription, @LayoutRes int tabLayout,
                 @AccessoryTabType int recordingType, @Nullable Listener listener) {
+            this(icon, contentDescription, null, tabLayout, recordingType, listener);
+        }
+
+        public Tab(Drawable icon, String contentDescription, @Nullable String openingAnnouncement,
+                @LayoutRes int tabLayout, @AccessoryTabType int recordingType,
+                @Nullable Listener listener) {
             mIcon = icon;
             mContentDescription = contentDescription;
+            mOpeningAnnouncement = openingAnnouncement;
             mTabLayout = tabLayout;
             mListener = listener;
             mRecordingType = recordingType;
@@ -102,15 +110,23 @@
 
         /**
          * The description for this tab. It will become the content description of the icon.
-         * @return A short string describing the task of this tab.
+         * @return A short string describing the name of this tab.
          */
         public String getContentDescription() {
             return mContentDescription;
         }
 
         /**
-         * The description for this tab. It will become the content description of the icon.
-         * @return A short string describing the task of this tab.
+         * An optional announcement triggered when the Tab is opened.
+         * @return A string describing the contents of this tab.
+         */
+        public String getOpeningAnnouncement() {
+            return mOpeningAnnouncement;
+        }
+
+        /**
+         * Recording type of this tab. Used to sort it into the correct UMA bucket.
+         * @return A {@link AccessoryTabType}.
          */
         public @AccessoryTabType int getRecordingType() {
             return mRecordingType;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryView.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryView.java
index d0be972..df50d78 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryView.java
@@ -9,6 +9,7 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.support.annotation.StringRes;
 import android.support.design.widget.TabLayout;
 import android.support.v4.graphics.drawable.DrawableCompat;
 import android.support.v4.view.ViewPager;
@@ -16,7 +17,6 @@
 import android.support.v7.widget.RecyclerView;
 import android.util.AttributeSet;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.LinearLayout;
 
@@ -64,6 +64,14 @@
         // Apply RTL layout changes to the views children:
         ApiCompatibilityUtils.setLayoutDirection(mActionsView,
                 isLayoutRtl() ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
+
+        // Set listener's to touch/click events so they are not propagated to the page below.
+        setOnTouchListener((view, motionEvent) -> {
+            performClick(); // Setting a touch listener requires this call which is a NoOp.
+            return true; // Return that the motionEvent was consumed and needs no further handling.
+        });
+        setOnClickListener(view -> {});
+        setClickable(false); // Disables the "Double-tap to activate" Talkback reading.
     }
 
     void setVisible(boolean visible) {
@@ -136,10 +144,20 @@
         }
     }
 
+    public void setTabDescription(int i, String description) {
+        TabLayout.Tab tab = mTabLayout.getTabAt(i);
+        if (tab != null) tab.setContentDescription(description);
+    }
+
+    public void setTabDescription(int i, @StringRes int messageId) {
+        TabLayout.Tab tab = mTabLayout.getTabAt(i);
+        if (tab != null) tab.setContentDescription(messageId);
+    }
+
     private void show() {
         bringToFront(); // Needs to overlay every component and the bottom sheet - like a keyboard.
         setVisibility(View.VISIBLE);
-        announceForAccessibility(((ViewGroup) getParent()).getContentDescription());
+        announceForAccessibility(getContentDescription());
     }
 
     private void hide() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewBinder.java
index eb56988..6dc26c8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/KeyboardAccessoryViewBinder.java
@@ -99,9 +99,11 @@
                     .updateAllTabs(view, model.getTabList());
         } else if (propertyKey == PropertyKey.VISIBLE) {
             view.setActiveTabColor(model.activeTab());
+            setActiveTabHint(model, view);
             view.setVisible(model.isVisible());
         } else if (propertyKey == PropertyKey.ACTIVE_TAB) {
             view.setActiveTabColor(model.activeTab());
+            setActiveTabHint(model, view);
         } else if (propertyKey == PropertyKey.BOTTOM_OFFSET) {
             view.setBottomOffset(model.bottomOffset());
         } else if (propertyKey == PropertyKey.TAB_SELECTION_CALLBACKS) {
@@ -112,4 +114,19 @@
             assert false : "Every possible property update needs to be handled!";
         }
     }
+
+    private static void setActiveTabHint(KeyboardAccessoryModel model, KeyboardAccessoryView view) {
+        int activeTab = -1;
+        if (model.activeTab() != null) {
+            activeTab = model.activeTab();
+        }
+        for (int i = 0; i < model.getTabList().size(); ++i) {
+            Tab tab = model.getTabList().get(i);
+            if (activeTab == i) {
+                view.setTabDescription(i, R.string.keyboard_accessory_sheet_hide);
+            } else {
+                view.setTabDescription(i, tab.getContentDescription());
+            }
+        }
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java
index b87d7a0e9..8f8e415 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetCoordinator.java
@@ -71,6 +71,7 @@
         mContext = context;
         mTab = new KeyboardAccessoryData.Tab(IconProvider.getInstance().getIcon(mContext),
                 context.getString(R.string.password_accessory_sheet_toggle),
+                context.getString(R.string.password_accessory_sheet_opened),
                 R.layout.password_accessory_sheet, AccessoryTabType.PASSWORDS, this);
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewBinder.java
index 2935182..5f75d68 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/keyboard_accessory/PasswordAccessorySheetViewBinder.java
@@ -103,6 +103,8 @@
             } else {
                 getTextView().setOnClickListener(null);
             }
+            // |setOnClickListener| has set this to |true|, so update it afterwards.
+            getTextView().setClickable(item.getItemSelectedCallback() != null);
         }
     }
 
@@ -131,6 +133,7 @@
         @Override
         protected void bind(Item item) {
             super.bind(item);
+            getTextView().setClickable(true); // Ensures that "disabled" is announced.
             if (item.getItemSelectedCallback() == null) {
                 mSuggestionText.setEnabled(false);
                 mSuggestionText.setBackground(null);
@@ -147,7 +150,7 @@
             // Jelly Bean, so the padding should be set after the background.
             if (!item.isPassword()) {
                 setIconForBitmap(null); // Set the default icon, then try to get a better one.
-                item.fetchFavicon(this ::setIconForBitmap);
+                item.fetchFavicon(this::setIconForBitmap);
                 mSuggestionText.setPadding(mPadding, 0, mPadding, 0);
             } else {
                 ApiCompatibilityUtils.setCompoundDrawablesRelative(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/LayerTitleCache.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/LayerTitleCache.java
index ca4a423..2e032204 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/LayerTitleCache.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/LayerTitleCache.java
@@ -15,6 +15,7 @@
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.compositor.layouts.content.TitleBitmapFactory;
 import org.chromium.chrome.browser.favicon.FaviconHelper;
+import org.chromium.chrome.browser.favicon.FaviconHelper.DefaultFaviconHelper;
 import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.tab.Tab;
@@ -41,6 +42,7 @@
     private ResourceManager mResourceManager;
 
     private FaviconHelper mFaviconHelper;
+    private DefaultFaviconHelper mDefaultFaviconHelper;
 
     /** Responsible for building titles on light themes or standard tabs. */
     protected TitleBitmapFactory mStandardTitleBitmapFactory;
@@ -61,10 +63,9 @@
         mNativeLayerTitleCache = nativeInit(fadeWidthPx, faviconStartPaddingPx, faviconEndPaddingPx,
                 R.drawable.spinner, R.drawable.spinner_white);
         mFaviconSize = res.getDimensionPixelSize(R.dimen.compositor_tab_title_favicon_size);
-        mStandardTitleBitmapFactory =
-                new TitleBitmapFactory(context, false, R.drawable.default_favicon);
-        mDarkTitleBitmapFactory =
-                new TitleBitmapFactory(context, true, R.drawable.default_favicon_white);
+        mStandardTitleBitmapFactory = new TitleBitmapFactory(context, false);
+        mDarkTitleBitmapFactory = new TitleBitmapFactory(context, true);
+        mDefaultFaviconHelper = new DefaultFaviconHelper();
     }
 
     /**
@@ -119,9 +120,12 @@
     private String getUpdatedTitleInternal(Tab tab, String titleString,
             boolean fetchFaviconFromHistory) {
         final int tabId = tab.getId();
-        Bitmap originalFavicon = tab.getFavicon();
-
         boolean isDarkTheme = tab.isIncognito();
+        Bitmap originalFavicon = tab.getFavicon();
+        if (originalFavicon == null) {
+            originalFavicon = mDefaultFaviconHelper.getDefaultFaviconBitmap(
+                    mContext, tab.getUrl(), !isDarkTheme);
+        }
 
         boolean isRtl = tab.isTitleDirectionRtl();
         TitleBitmapFactory titleBitmapFactory =
@@ -135,8 +139,7 @@
         }
 
         title.set(titleBitmapFactory.getTitleBitmap(mContext, titleString),
-                titleBitmapFactory.getFaviconBitmap(mContext, originalFavicon),
-                fetchFaviconFromHistory);
+                titleBitmapFactory.getFaviconBitmap(originalFavicon), fetchFaviconFromHistory);
 
         if (mNativeLayerTitleCache != 0) {
             nativeUpdateLayer(mNativeLayerTitleCache, tabId, title.getTitleResId(),
@@ -216,6 +219,7 @@
             toDelete.unregister();
         }
         mTitles.clear();
+        mDefaultFaviconHelper.clearCache();
 
         if (title != null) mTitles.put(exceptId, title);
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TitleBitmapFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TitleBitmapFactory.java
index 1cd2b42..c101a860 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TitleBitmapFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/content/TitleBitmapFactory.java
@@ -10,8 +10,6 @@
 import android.graphics.Canvas;
 import android.graphics.Paint;
 import android.graphics.Paint.FontMetrics;
-import android.graphics.drawable.BitmapDrawable;
-import android.graphics.drawable.Drawable;
 import android.text.Layout;
 import android.text.TextPaint;
 import android.text.TextUtils;
@@ -33,7 +31,6 @@
     private static final int MAX_NUM_TITLE_CHAR = 1000;
 
     private final int mMaxWidth;
-    private final int mNullFaviconResourceId;
 
     private final TextPaint mTextPaint;
     private int mFaviconDimension;
@@ -44,11 +41,8 @@
     /**
      * @param context   The current Android's context.
      * @param incognito Whether the title are for incognito mode.
-     * @param nullFaviconResourceId A drawable resource id of a default favicon.
      */
-    public TitleBitmapFactory(Context context, boolean incognito, int nullFaviconResourceId) {
-        mNullFaviconResourceId = nullFaviconResourceId;
-
+    public TitleBitmapFactory(Context context, boolean incognito) {
         Resources res = context.getResources();
         int textColor = ApiCompatibilityUtils.getColor(res, incognito
                 ? R.color.compositor_tab_title_bar_text_incognito
@@ -82,26 +76,24 @@
     /**
      * Generates the favicon bitmap.
      *
-     * @param context   Android's UI context.
      * @param favicon   The favicon of the tab.
      * @return          The Bitmap with the favicon.
      */
-    public Bitmap getFaviconBitmap(Context context, Bitmap favicon) {
+    public Bitmap getFaviconBitmap(Bitmap favicon) {
+        assert favicon != null;
         try {
             Bitmap b = Bitmap.createBitmap(
                     mFaviconDimension, mFaviconDimension, Bitmap.Config.ARGB_8888);
             Canvas c = new Canvas(b);
-            if (favicon == null) {
-                Drawable drawable = ApiCompatibilityUtils.getDrawable(
-                        context.getResources(), mNullFaviconResourceId);
-                if (drawable instanceof BitmapDrawable) {
-                    favicon = ((BitmapDrawable) drawable).getBitmap();
-                }
+            if (favicon.getWidth() > mFaviconDimension || favicon.getHeight() > mFaviconDimension) {
+                float scale = (float) mFaviconDimension
+                        / Math.max(favicon.getWidth(), favicon.getHeight());
+                c.scale(scale, scale);
+            } else {
+                c.translate(Math.round((mFaviconDimension - favicon.getWidth()) / 2.0f),
+                        Math.round((mFaviconDimension - favicon.getHeight()) / 2.0f));
             }
-            if (favicon != null) {
-                c.drawBitmap(favicon, Math.round((mFaviconDimension - favicon.getWidth()) / 2.0f),
-                        Math.round((mFaviconDimension - favicon.getHeight()) / 2.0f), null);
-            }
+            c.drawBitmap(favicon, 0, 0, null);
             return b;
         } catch (OutOfMemoryError ex) {
             Log.e(TAG, "OutOfMemoryError while building favicon texture.");
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 547354bb..bbd9cc6 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
@@ -15,7 +15,6 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.StrictMode;
 import android.os.SystemClock;
@@ -47,7 +46,6 @@
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.metrics.RecordUserAction;
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ActivityTabTaskDescriptionHelper;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.ChromeSwitches;
@@ -197,19 +195,6 @@
     private boolean mModuleOnResumePending;
     private boolean mHasSetOverlayView;
 
-    private ActivityTabTaskDescriptionHelper mTaskDescriptionHelper;
-
-    /**
-     * Return true when the activity has been launched in a separate task. The default behavior is
-     * to reuse the same task and put the activity on top of the previous one (i.e hiding it). A
-     * separate task creates a new entry in the Android recent screen.
-     **/
-    private boolean useSeparateTask() {
-        final int separateTaskFlags =
-                Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
-        return (getIntent().getFlags() & separateTaskFlags) != 0;
-    }
-
     private TabModelObserver mCloseActivityWhenEmptyTabModelObserver = new EmptyTabModelObserver() {
         @Override
         public void didCloseTab(int tabId, boolean incognito) {
@@ -683,11 +668,6 @@
             mTrustedWebActivityUi.initialShowSnackbarIfNeeded();
         }
 
-        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && useSeparateTask()) {
-            mTaskDescriptionHelper = new ActivityTabTaskDescriptionHelper(this,
-                    ApiCompatibilityUtils.getColor(getResources(), R.color.default_primary_color));
-        }
-
         super.finishNativeInitialization();
     }
 
@@ -930,8 +910,6 @@
         if (mIncognitoTabHost != null) {
             IncognitoTabHostRegistry.getInstance().unregister(mIncognitoTabHost);
         }
-
-        if (mTaskDescriptionHelper != null) mTaskDescriptionHelper.destroy();
     }
 
     @Override
@@ -1101,11 +1079,8 @@
      * recents.
      */
     protected void handleFinishAndClose() {
-        if (useSeparateTask()) {
-            ApiCompatibilityUtils.finishAndRemoveTask(this);
-        } else {
-            finish();
-        }
+        // When on top of another app, finish is all that is required.
+        finish();
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/SeparateTaskCustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/SeparateTaskCustomTabActivity.java
index 0fb36fa..caa39bc 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/SeparateTaskCustomTabActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/SeparateTaskCustomTabActivity.java
@@ -3,11 +3,39 @@
 // found in the LICENSE file.
 
 package org.chromium.chrome.browser.customtabs;
+
+import android.os.Build;
+
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ActivityTabTaskDescriptionHelper;
+
 /**
- * Wrapper around the CustomTabActivity for Android version pre L to be used when launching
- * each CustomTab in a separate task. This class is copied 10 times as
- * SeparateTaskCustomTabActivity${i} to "emulate" having multi task being supported.
- *
- * TODO(arthursonzogni, tedchoc): Remove this after M74.
+ * Simple wrapper around the CustomTabActivity to be used when launching each CustomTab in a
+ * separate task.
  */
-public class SeparateTaskCustomTabActivity extends CustomTabActivity {}
+public class SeparateTaskCustomTabActivity extends CustomTabActivity {
+    private ActivityTabTaskDescriptionHelper mTaskDescriptionHelper;
+
+    @Override
+    public void finishNativeInitialization() {
+        super.finishNativeInitialization();
+
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+            mTaskDescriptionHelper = new ActivityTabTaskDescriptionHelper(this,
+                    ApiCompatibilityUtils.getColor(getResources(), R.color.default_primary_color));
+        }
+    }
+
+    @Override
+    protected void onDestroyInternal() {
+        super.onDestroyInternal();
+
+        if (mTaskDescriptionHelper != null) mTaskDescriptionHelper.destroy();
+    }
+
+    @Override
+    protected void handleFinishAndClose() {
+        ApiCompatibilityUtils.finishAndRemoveTask(this);
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/empty/EmptyCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/empty/EmptyCoordinator.java
index 5bab5f9..97a923b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/empty/EmptyCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/empty/EmptyCoordinator.java
@@ -102,12 +102,12 @@
                 textId = R.string.download_manager_ui_empty;
             }
 
-            mModel.setValue(EmptyProperties.EMPTY_TEXT_RES_ID, textId);
-            mModel.setValue(EmptyProperties.EMPTY_ICON_RES_ID, iconId);
+            mModel.set(EmptyProperties.EMPTY_TEXT_RES_ID, textId);
+            mModel.set(EmptyProperties.EMPTY_ICON_RES_ID, iconId);
         } else {
             state = State.GONE;
         }
 
-        mModel.setValue(EmptyProperties.STATE, state);
+        mModel.set(EmptyProperties.STATE, state);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/empty/EmptyViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/empty/EmptyViewBinder.java
index e07d9525..8c14b29b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/empty/EmptyViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/empty/EmptyViewBinder.java
@@ -16,11 +16,11 @@
     @Override
     public void bind(PropertyModel model, EmptyView view, PropertyKey propertyKey) {
         if (propertyKey == EmptyProperties.STATE) {
-            view.setState(model.getValue(EmptyProperties.STATE));
+            view.setState(model.get(EmptyProperties.STATE));
         } else if (propertyKey == EmptyProperties.EMPTY_TEXT_RES_ID) {
-            view.setEmptyText(model.getValue(EmptyProperties.EMPTY_TEXT_RES_ID));
+            view.setEmptyText(model.get(EmptyProperties.EMPTY_TEXT_RES_ID));
         } else if (propertyKey == EmptyProperties.EMPTY_ICON_RES_ID) {
-            view.setEmptyIcon(model.getValue(EmptyProperties.EMPTY_ICON_RES_ID));
+            view.setEmptyIcon(model.get(EmptyProperties.EMPTY_ICON_RES_ID));
         }
     }
 }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterCoordinator.java
index a81e008..1a6a1c5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterCoordinator.java
@@ -52,10 +52,10 @@
         mView = new FilterView(context);
         PropertyModelChangeProcessor.create(mModel, mView, new FilterViewBinder());
 
-        mModel.setValue(FilterProperties.CHANGE_LISTENER, this::handleTabSelected);
+        mModel.set(FilterProperties.CHANGE_LISTENER, this::handleTabSelected);
         selectTab(TabType.FILES);
 
-        mModel.setValue(FilterProperties.SHOW_TABS, prefetchStatusProvider.enabled());
+        mModel.set(FilterProperties.SHOW_TABS, prefetchStatusProvider.enabled());
     }
 
     /** @return The {@link View} representing this widget. */
@@ -87,12 +87,12 @@
     }
 
     private void selectTab(@TabType int selectedTab) {
-        mModel.setValue(FilterProperties.SELECTED_TAB, selectedTab);
+        mModel.set(FilterProperties.SELECTED_TAB, selectedTab);
 
         if (selectedTab == TabType.FILES) {
-            mModel.setValue(FilterProperties.CONTENT_VIEW, mChipsCoordinator.getView());
+            mModel.set(FilterProperties.CONTENT_VIEW, mChipsCoordinator.getView());
         } else if (selectedTab == TabType.PREFETCH) {
-            mModel.setValue(FilterProperties.CONTENT_VIEW, null);
+            mModel.set(FilterProperties.CONTENT_VIEW, null);
         }
     }
 
@@ -115,6 +115,6 @@
     }
 
     private void handleChipSelected() {
-        handleTabSelected(mModel.getValue(FilterProperties.SELECTED_TAB));
+        handleTabSelected(mModel.get(FilterProperties.SELECTED_TAB));
     }
 }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterViewBinder.java
index b8aebad7..db6cd9d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/filter/FilterViewBinder.java
@@ -16,13 +16,13 @@
     @Override
     public void bind(PropertyModel model, FilterView view, PropertyKey propertyKey) {
         if (propertyKey == FilterProperties.CONTENT_VIEW) {
-            view.setContentView(model.getValue(FilterProperties.CONTENT_VIEW));
+            view.setContentView(model.get(FilterProperties.CONTENT_VIEW));
         } else if (propertyKey == FilterProperties.SELECTED_TAB) {
-            view.setTabSelected(model.getValue(FilterProperties.SELECTED_TAB));
+            view.setTabSelected(model.get(FilterProperties.SELECTED_TAB));
         } else if (propertyKey == FilterProperties.CHANGE_LISTENER) {
-            view.setTabSelectedCallback(model.getValue(FilterProperties.CHANGE_LISTENER));
+            view.setTabSelectedCallback(model.get(FilterProperties.CHANGE_LISTENER));
         } else if (propertyKey == FilterProperties.SHOW_TABS) {
-            view.setShowTabs(model.getValue(FilterProperties.SHOW_TABS));
+            view.setShowTabs(model.get(FilterProperties.SHOW_TABS));
         }
     }
 }
\ No newline at end of file
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java
index de948ca..f9a374a6 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java
@@ -94,7 +94,7 @@
                 mModel.update(i, item);
             }
             mModel.dispatchLastEvent();
-            mModel.getProperties().setValue(
+            mModel.getProperties().set(
                     ListProperties.SELECTION_MODE_ACTIVE, mSelectionDelegate.isSelectionEnabled());
         }
     }
@@ -143,16 +143,16 @@
                 ((ChromeApplication) ContextUtils.getApplicationContext()).getReferencePool());
         mSelectionObserver = new MediatorSelectionObserver(selectionDelegate);
 
-        mModel.getProperties().setValue(ListProperties.ENABLE_ITEM_ANIMATIONS, true);
-        mModel.getProperties().setValue(ListProperties.CALLBACK_OPEN, mProvider::openItem);
-        mModel.getProperties().setValue(ListProperties.CALLBACK_PAUSE, mProvider::pauseDownload);
-        mModel.getProperties().setValue(
+        mModel.getProperties().set(ListProperties.ENABLE_ITEM_ANIMATIONS, true);
+        mModel.getProperties().set(ListProperties.CALLBACK_OPEN, mProvider::openItem);
+        mModel.getProperties().set(ListProperties.CALLBACK_PAUSE, mProvider::pauseDownload);
+        mModel.getProperties().set(
                 ListProperties.CALLBACK_RESUME, item -> mProvider.resumeDownload(item, true));
-        mModel.getProperties().setValue(ListProperties.CALLBACK_CANCEL, mProvider::cancelDownload);
-        mModel.getProperties().setValue(ListProperties.CALLBACK_SHARE, this ::onShareItem);
-        mModel.getProperties().setValue(ListProperties.CALLBACK_REMOVE, this ::onDeleteItem);
-        mModel.getProperties().setValue(ListProperties.PROVIDER_VISUALS, this ::getVisuals);
-        mModel.getProperties().setValue(
+        mModel.getProperties().set(ListProperties.CALLBACK_CANCEL, mProvider::cancelDownload);
+        mModel.getProperties().set(ListProperties.CALLBACK_SHARE, this ::onShareItem);
+        mModel.getProperties().set(ListProperties.CALLBACK_REMOVE, this ::onDeleteItem);
+        mModel.getProperties().set(ListProperties.PROVIDER_VISUALS, this ::getVisuals);
+        mModel.getProperties().set(
                 ListProperties.CALLBACK_SELECTION, selectionDelegate::toggleSelectionForItem);
     }
 
@@ -288,14 +288,14 @@
     /** Helper class to disable animations for certain list changes. */
     private class AnimationDisableClosable implements Closeable {
         AnimationDisableClosable() {
-            mModel.getProperties().setValue(ListProperties.ENABLE_ITEM_ANIMATIONS, false);
+            mModel.getProperties().set(ListProperties.ENABLE_ITEM_ANIMATIONS, false);
         }
 
         // Closeable implementation.
         @Override
         public void close() {
             mHandler.post(() -> {
-                mModel.getProperties().setValue(ListProperties.ENABLE_ITEM_ANIMATIONS, true);
+                mModel.getProperties().set(ListProperties.ENABLE_ITEM_ANIMATIONS, true);
             });
         }
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListPropertyViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListPropertyViewBinder.java
index 00bcf87..71eb179 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListPropertyViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/ListPropertyViewBinder.java
@@ -16,7 +16,7 @@
     @Override
     public void bind(PropertyModel model, RecyclerView view, PropertyKey propertyKey) {
         if (propertyKey == ListProperties.ENABLE_ITEM_ANIMATIONS) {
-            if (model.getValue(ListProperties.ENABLE_ITEM_ANIMATIONS)) {
+            if (model.get(ListProperties.ENABLE_ITEM_ANIMATIONS)) {
                 if (view.getItemAnimator() == null) {
                     view.setItemAnimator((ItemAnimator) view.getTag(R.id.item_animator));
                     view.setTag(R.id.item_animator, null);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/InProgressViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/InProgressViewHolder.java
index c7376ac5..86f5ef8c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/InProgressViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/InProgressViewHolder.java
@@ -53,8 +53,8 @@
     public void bind(PropertyModel properties, ListItem item) {
         ListItem.OfflineItemListItem offlineItem = (ListItem.OfflineItemListItem) item;
         mTitle.setText(offlineItem.item.title);
-        mCancelButton.setOnClickListener(v
-                -> properties.getValue(ListProperties.CALLBACK_CANCEL).onResult(offlineItem.item));
+        mCancelButton.setOnClickListener(
+                v -> properties.get(ListProperties.CALLBACK_CANCEL).onResult(offlineItem.item));
 
         if (offlineItem.item.state == OfflineItemState.PAUSED) {
             mPauseResumeButton.setImageResource(R.drawable.ic_play_arrow_white_24dp);
@@ -70,9 +70,9 @@
         mCaption.setText(DownloadUtils.getProgressTextForNotification(offlineItem.item.progress));
         mPauseResumeButton.setOnClickListener(view -> {
             if (offlineItem.item.state == OfflineItemState.PAUSED) {
-                properties.getValue(ListProperties.CALLBACK_RESUME).onResult(offlineItem.item);
+                properties.get(ListProperties.CALLBACK_RESUME).onResult(offlineItem.item);
             } else {
-                properties.getValue(ListProperties.CALLBACK_PAUSE).onResult(offlineItem.item);
+                properties.get(ListProperties.CALLBACK_PAUSE).onResult(offlineItem.item);
             }
         });
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/MoreButtonViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/MoreButtonViewHolder.java
index 434a3a4..45cdd9f3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/MoreButtonViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/MoreButtonViewHolder.java
@@ -37,11 +37,11 @@
     public void bind(PropertyModel properties, ListItem item) {
         ListItem.OfflineItemListItem offlineItem = (ListItem.OfflineItemListItem) item;
         mShareCallback =
-                () -> properties.getValue(ListProperties.CALLBACK_SHARE).onResult(offlineItem.item);
-        mDeleteCallback = ()
-                -> properties.getValue(ListProperties.CALLBACK_REMOVE).onResult(offlineItem.item);
+                () -> properties.get(ListProperties.CALLBACK_SHARE).onResult(offlineItem.item);
+        mDeleteCallback =
+                () -> properties.get(ListProperties.CALLBACK_REMOVE).onResult(offlineItem.item);
         if (mMore != null) {
-            mMore.setClickable(!properties.getValue(ListProperties.SELECTION_MODE_ACTIVE));
+            mMore.setClickable(!properties.get(ListProperties.SELECTION_MODE_ACTIVE));
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/ThumbnailAwareViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/ThumbnailAwareViewHolder.java
index edcbf02f..57e0db7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/ThumbnailAwareViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/holder/ThumbnailAwareViewHolder.java
@@ -83,20 +83,20 @@
 
         if (mSelectionView != null) {
             mSelectionView.setSelectionState(item.selected,
-                    properties.getValue(ListProperties.SELECTION_MODE_ACTIVE),
+                    properties.get(ListProperties.SELECTION_MODE_ACTIVE),
                     item.showSelectedAnimation);
         }
 
         itemView.setOnLongClickListener(v -> {
-            properties.getValue(ListProperties.CALLBACK_SELECTION).onResult(item);
+            properties.get(ListProperties.CALLBACK_SELECTION).onResult(item);
             return true;
         });
 
         itemView.setOnClickListener(v -> {
             if (mSelectionView != null && mSelectionView.isInSelectionMode()) {
-                properties.getValue(ListProperties.CALLBACK_SELECTION).onResult(item);
+                properties.get(ListProperties.CALLBACK_SELECTION).onResult(item);
             } else {
-                properties.getValue(ListProperties.CALLBACK_OPEN).onResult(offlineItem);
+                properties.get(ListProperties.CALLBACK_OPEN).onResult(offlineItem);
             }
         });
 
@@ -111,7 +111,7 @@
 
         // Start the new request.
         mId = offlineItem.id;
-        mCancellable = properties.getValue(ListProperties.PROVIDER_VISUALS)
+        mCancellable = properties.get(ListProperties.PROVIDER_VISUALS)
                                .getVisuals(offlineItem, mWidthPx, mHeightPx, this);
 
         // Make sure to update our state properly if we got a synchronous response.
@@ -123,7 +123,7 @@
 
         return mSelectionView.isSelected() != item.selected
                 || mSelectionView.isInSelectionMode()
-                != properties.getValue(ListProperties.SELECTION_MODE_ACTIVE);
+                != properties.get(ListProperties.SELECTION_MODE_ACTIVE);
     }
 
     // VisualsCallback implementation.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/storage/StorageCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/storage/StorageCoordinator.java
index 4c41d1b1..5f6ed9b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/storage/StorageCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/storage/StorageCoordinator.java
@@ -36,12 +36,12 @@
     }
 
     private void onStorageInfoUpdated(String storageInfoText) {
-        mModel.setValue(StorageProperties.STORAGE_INFO_TEXT, storageInfoText);
+        mModel.set(StorageProperties.STORAGE_INFO_TEXT, storageInfoText);
     }
 
     private void bind(PropertyModel model, TextView view, PropertyKey propertyKey) {
         if (propertyKey == StorageProperties.STORAGE_INFO_TEXT) {
-            view.setText(model.getValue(StorageProperties.STORAGE_INFO_TEXT));
+            view.setText(model.get(StorageProperties.STORAGE_INFO_TEXT));
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/favicon/FaviconHelper.java b/chrome/android/java/src/org/chromium/chrome/browser/favicon/FaviconHelper.java
index 586742b2..8ba2e5a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/favicon/FaviconHelper.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/favicon/FaviconHelper.java
@@ -4,9 +4,21 @@
 
 package org.chromium.chrome.browser.favicon;
 
+import android.content.Context;
 import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.support.annotation.ColorInt;
 
+import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.annotations.CalledByNative;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ntp.NewTabPage;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.content_public.browser.WebContents;
 
@@ -49,6 +61,81 @@
     }
 
     /**
+     * Helper for generating default favicons and sharing the same icon between multiple views.
+     */
+    public static class DefaultFaviconHelper {
+        private Bitmap mChromeDarkBitmap;
+        private Bitmap mChromeLightBitmap;
+        private Bitmap mDefaultDarkBitmap;
+        private Bitmap mDefaultLightBitmap;
+
+        private int getResourceId(String url) {
+            return NewTabPage.isNTPUrl(url) ? R.drawable.chromelogo16 : R.drawable.default_favicon;
+        }
+
+        private Bitmap createBitmap(Context context, String url, boolean useDarkIcon) {
+            Bitmap origBitmap =
+                    BitmapFactory.decodeResource(context.getResources(), getResourceId(url));
+            Bitmap tintedBitmap = Bitmap.createBitmap(
+                    origBitmap.getWidth(), origBitmap.getHeight(), Bitmap.Config.ARGB_8888);
+            Canvas c = new Canvas(tintedBitmap);
+            @ColorInt
+            int tintColor = ApiCompatibilityUtils.getColor(context.getResources(),
+                    useDarkIcon ? R.color.default_icon_color : R.color.default_icon_color_white);
+            Paint p = new Paint();
+            p.setColorFilter(new PorterDuffColorFilter(tintColor, PorterDuff.Mode.SRC_IN));
+            c.drawBitmap(origBitmap, 0f, 0f, p);
+            return tintedBitmap;
+        }
+
+        /**
+         * Generate a default favicon bitmap for the given URL.
+         * @param context The context used to fetch the default icons.
+         * @param url The URL of the page whose icon is being generated.
+         * @param useDarkIcon Whether a dark icon should be used.
+         * @return The favicon.
+         */
+        public Bitmap getDefaultFaviconBitmap(Context context, String url, boolean useDarkIcon) {
+            boolean isNtp = NewTabPage.isNTPUrl(url);
+            Bitmap bitmap = isNtp ? (useDarkIcon ? mChromeDarkBitmap : mChromeLightBitmap)
+                                  : (useDarkIcon ? mDefaultDarkBitmap : mDefaultLightBitmap);
+            if (bitmap != null) return bitmap;
+            bitmap = createBitmap(context, url, useDarkIcon);
+            if (isNtp && useDarkIcon) {
+                mChromeDarkBitmap = bitmap;
+            } else if (isNtp) {
+                mChromeLightBitmap = bitmap;
+            } else if (useDarkIcon) {
+                mDefaultDarkBitmap = bitmap;
+            } else {
+                mDefaultLightBitmap = bitmap;
+            }
+            return bitmap;
+        }
+
+        /**
+         * Generate a default favicon drawable for the given URL.
+         * @param context The context used to fetch the default icons.
+         * @param url The URL of the page whose icon is being generated.
+         * @param useDarkIcon Whether a dark icon should be used.
+         * @return The favicon.
+         */
+        public Drawable getDefaultFaviconDrawable(
+                Context context, String url, boolean useDarkIcon) {
+            return new BitmapDrawable(
+                    context.getResources(), getDefaultFaviconBitmap(context, url, useDarkIcon));
+        }
+
+        /** Clears any of the cached default drawables. */
+        public void clearCache() {
+            mChromeDarkBitmap = null;
+            mChromeLightBitmap = null;
+            mDefaultDarkBitmap = null;
+            mDefaultLightBitmap = null;
+        }
+    }
+
+    /**
      * Allocate and initialize the C++ side of this class.
      */
     public FaviconHelper() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryAdapter.java
index 1c3e1bb..8c22653 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryAdapter.java
@@ -20,6 +20,7 @@
 import org.chromium.base.VisibleForTesting;
 import org.chromium.chrome.R;
 import org.chromium.chrome.browser.UrlConstants;
+import org.chromium.chrome.browser.favicon.FaviconHelper.DefaultFaviconHelper;
 import org.chromium.chrome.browser.history.HistoryProvider.BrowsingHistoryObserver;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.preferences.PrefServiceBridge;
@@ -43,6 +44,7 @@
     private final HistoryProvider mHistoryProvider;
     private final HistoryManager mHistoryManager;
     private final ArrayList<HistoryItemView> mItemViews;
+    private final DefaultFaviconHelper mFaviconHelper;
     private RecyclerView mRecyclerView;
 
     private View mPrivacyDisclaimerBottomSpace;
@@ -68,6 +70,7 @@
         mHistoryProvider = provider;
         mHistoryProvider.setObserver(this);
         mHistoryManager = manager;
+        mFaviconHelper = new DefaultFaviconHelper();
         mItemViews = new ArrayList<>();
     }
 
@@ -78,6 +81,7 @@
         mHistoryProvider.destroy();
         mIsDestroyed = true;
         mRecyclerView = null;
+        mFaviconHelper.clearCache();
     }
 
     /**
@@ -193,6 +197,7 @@
                 new SelectableItemViewHolder<>(v, mSelectionDelegate);
         HistoryItemView itemView = (HistoryItemView) viewHolder.itemView;
         itemView.setRemoveButtonVisible(!mSelectionDelegate.isSelectionEnabled());
+        itemView.setFaviconHelper(mFaviconHelper);
         mItemViews.add(itemView);
         return viewHolder;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryItemView.java b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryItemView.java
index 6fcc25dd..c4eadf06 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryItemView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/history/HistoryItemView.java
@@ -16,6 +16,7 @@
 
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.favicon.FaviconHelper.DefaultFaviconHelper;
 import org.chromium.chrome.browser.favicon.IconType;
 import org.chromium.chrome.browser.favicon.LargeIconBridge.LargeIconCallback;
 import org.chromium.chrome.browser.preferences.Pref;
@@ -36,6 +37,7 @@
 
     private HistoryManager mHistoryManager;
     private final RoundedIconGenerator mIconGenerator;
+    private DefaultFaviconHelper mFaviconHelper;
 
     private final int mMinIconSize;
     private final int mDisplayedIconSize;
@@ -94,7 +96,7 @@
                     ApiCompatibilityUtils.getColor(getResources(), R.color.google_red_700));
         } else {
             setIconDrawable(
-                    ApiCompatibilityUtils.getDrawable(getResources(), R.drawable.default_favicon));
+                    mFaviconHelper.getDefaultFaviconDrawable(getContext(), item.getUrl(), true));
             if (mHistoryManager != null) requestIcon();
 
             mTitleView.setTextColor(
@@ -114,6 +116,13 @@
     }
 
     /**
+     * @param helper The helper for fetching default favicons.
+     */
+    public void setFaviconHelper(DefaultFaviconHelper helper) {
+        mFaviconHelper = helper;
+    }
+
+    /**
      * Removes the item associated with this view.
      */
     public void remove() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java b/chrome/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java
index 6906344..310f463 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/language/LanguageAskPrompt.java
@@ -98,10 +98,13 @@
      */
     public static boolean maybeShowLanguageAskPrompt(ChromeActivity activity) {
         if (!ChromeFeatureList.isEnabled(ChromeFeatureList.EXPLICIT_LANGUAGE_ASK)) return false;
+        if (PrefServiceBridge.getInstance().getExplicitLanguageAskPromptShown()) return false;
 
         LanguageAskPrompt prompt = new LanguageAskPrompt();
         prompt.show(activity);
 
+        PrefServiceBridge.getInstance().setExplicitLanguageAskPromptShown(true);
+
         return true;
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityTabStartupMetricsTracker.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityTabStartupMetricsTracker.java
index 99e79f6..e77d5f3e7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityTabStartupMetricsTracker.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/ActivityTabStartupMetricsTracker.java
@@ -40,10 +40,9 @@
                 .addStartupCompletedObserver(new BrowserStartupController.StartupCallback() {
                     @Override
                     public void onSuccess() {
-                        // Activity could have called finish and returned early during startup but
-                        // not have onDestroy called yet. The activity's TabModelSelector may not
-                        // have been initialized causing a crash. See https://crbug.com/847580
-                        if (mActivity.isActivityFinishing()) return;
+                        // The activity's TabModelSelector may not have been initialized yet
+                        // causing a crash. See https://crbug.com/847580
+                        if (!mActivity.areTabModelsInitialized()) return;
                         registerObservers();
                     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java
index dd7c3015..fb8b0bb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/metrics/UmaUtils.java
@@ -95,6 +95,11 @@
         return sForegroundStartTimeMs;
     }
 
+    @CalledByNative
+    private static void setUsageAndCrashReportingFromNative(boolean enabled) {
+        UmaSessionStats.changeMetricsReportingConsent(enabled);
+    }
+
     private static native boolean nativeIsClientInMetricsReportingSample();
     private static native void nativeRecordMetricsReportingDefaultOptIn(boolean optIn);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/modelutil/LazyConstructionPropertyMcp.java b/chrome/android/java/src/org/chromium/chrome/browser/modelutil/LazyConstructionPropertyMcp.java
index 529455bc..78bed8a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/modelutil/LazyConstructionPropertyMcp.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/modelutil/LazyConstructionPropertyMcp.java
@@ -63,7 +63,7 @@
                     ViewProvider<V> viewFactory,
                     PropertyModelChangeProcessor.ViewBinder<M, V, PropertyKey> viewBinder) {
         return new LazyConstructionPropertyMcp<>(model, visibilityProperty,
-                item -> item.getValue(visibilityProperty), viewFactory, viewBinder);
+                item -> item.get(visibilityProperty), viewFactory, viewBinder);
     }
 
     private void flushPendingUpdates() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/modelutil/PropertyModel.java b/chrome/android/java/src/org/chromium/chrome/browser/modelutil/PropertyModel.java
index 627e23c..f6653513 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/modelutil/PropertyModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/modelutil/PropertyModel.java
@@ -58,7 +58,7 @@
     /**
      * Get the current value from the float based key.
      */
-    public float getValue(FloatPropertyKey key) {
+    public float get(FloatPropertyKey key) {
         validateKey(key);
         FloatContainer container = (FloatContainer) mData.get(key);
         return container == null ? 0f : container.value;
@@ -67,7 +67,7 @@
     /**
      * Set the value for the float based key.
      */
-    public void setValue(FloatPropertyKey key, float value) {
+    public void set(FloatPropertyKey key, float value) {
         validateKey(key);
         FloatContainer container = (FloatContainer) mData.get(key);
         if (container == null) {
@@ -83,7 +83,7 @@
     /**
      * Get the current value from the int based key.
      */
-    public int getValue(IntPropertyKey key) {
+    public int get(IntPropertyKey key) {
         validateKey(key);
         IntContainer container = (IntContainer) mData.get(key);
         return container == null ? 0 : container.value;
@@ -92,7 +92,7 @@
     /**
      * Set the value for the int based key.
      */
-    public void setValue(IntPropertyKey key, int value) {
+    public void set(IntPropertyKey key, int value) {
         validateKey(key);
         IntContainer container = (IntContainer) mData.get(key);
         if (container == null) {
@@ -108,7 +108,7 @@
     /**
      * Get the current value from the boolean based key.
      */
-    public boolean getValue(BooleanPropertyKey key) {
+    public boolean get(BooleanPropertyKey key) {
         validateKey(key);
         BooleanContainer container = (BooleanContainer) mData.get(key);
         return container == null ? false : container.value;
@@ -117,7 +117,7 @@
     /**
      * Set the value for the boolean based key.
      */
-    public void setValue(BooleanPropertyKey key, boolean value) {
+    public void set(BooleanPropertyKey key, boolean value) {
         validateKey(key);
         BooleanContainer container = (BooleanContainer) mData.get(key);
         if (container == null) {
@@ -134,7 +134,7 @@
      * Get the current value from the object based key.
      */
     @SuppressWarnings("unchecked")
-    public <T> T getValue(ObjectPropertyKey<T> key) {
+    public <T> T get(ObjectPropertyKey<T> key) {
         validateKey(key);
         ObjectContainer<T> container = (ObjectContainer<T>) mData.get(key);
         return container == null ? null : container.value;
@@ -144,7 +144,7 @@
      * Set the value for the Object based key.
      */
     @SuppressWarnings("unchecked")
-    public <T> void setValue(ObjectPropertyKey<T> key, T value) {
+    public <T> void set(ObjectPropertyKey<T> key, T value) {
         validateKey(key);
         ObjectContainer<T> container = (ObjectContainer<T>) mData.get(key);
         if (container == null) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java
index ddb6881..12c7516 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/RecentTabsRowAdapter.java
@@ -22,9 +22,9 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
-import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.favicon.FaviconHelper.DefaultFaviconHelper;
 import org.chromium.chrome.browser.favicon.FaviconHelper.FaviconImageCallback;
 import org.chromium.chrome.browser.ntp.ForeignSessionHelper.ForeignSession;
 import org.chromium.chrome.browser.ntp.ForeignSessionHelper.ForeignSessionTab;
@@ -100,7 +100,7 @@
 
     private final Activity mActivity;
     private final List<Group> mGroups;
-    private final Drawable mDefaultFavicon;
+    private final DefaultFaviconHelper mDefaultFaviconHelper;
     private final RecentTabsManager mRecentTabsManager;
     private final RecentlyClosedTabsGroup mRecentlyClosedTabsGroup = new RecentlyClosedTabsGroup();
     private final SeparatorGroup mVisibleSeparatorGroup = new SeparatorGroup(true);
@@ -678,7 +678,7 @@
         mFaviconCache = new FaviconCache(MAX_NUM_FAVICONS_TO_CACHE);
 
         Resources resources = activity.getResources();
-        mDefaultFavicon = ApiCompatibilityUtils.getDrawable(resources, R.drawable.default_favicon);
+        mDefaultFaviconHelper = new DefaultFaviconHelper();
         mFaviconSize = resources.getDimensionPixelSize(R.dimen.default_favicon_size);
 
         mIconGenerator = ViewUtils.createDefaultRoundedIconGenerator(
@@ -723,7 +723,9 @@
         Drawable image = mFaviconCache.getSyncedFaviconImage(url);
         if (image == null) {
             image = faviconDrawable(mRecentTabsManager.getSyncedFaviconImageForURL(url), url);
-            image = (image == null) ? mDefaultFavicon : image;
+            image = (image == null)
+                    ? mDefaultFaviconHelper.getDefaultFaviconDrawable(mActivity, url, true)
+                    : image;
             mFaviconCache.putSyncedFaviconImage(url, image);
         }
         viewHolder.imageView.setImageDrawable(image);
@@ -733,7 +735,7 @@
         Drawable image;
         if (url == null) {
             // URL is null for print jobs, for example.
-            image = mDefaultFavicon;
+            image = mDefaultFaviconHelper.getDefaultFaviconDrawable(mActivity, url, true);
         } else {
             image = mFaviconCache.getLocalFaviconImage(url);
             if (image == null) {
@@ -742,14 +744,16 @@
                     public void onFaviconAvailable(Bitmap bitmap, String iconUrl) {
                         if (this != viewHolder.imageCallback) return;
                         Drawable image = faviconDrawable(bitmap, url);
-                        image = (image == null) ? mDefaultFavicon : image;
+                        image = image == null ? mDefaultFaviconHelper.getDefaultFaviconDrawable(
+                                                        mActivity, url, true)
+                                              : image;
                         mFaviconCache.putLocalFaviconImage(url, image);
                         viewHolder.imageView.setImageDrawable(image);
                     }
                 };
                 viewHolder.imageCallback = imageCallback;
                 mRecentTabsManager.getLocalFaviconForUrl(url, mFaviconSize, imageCallback);
-                image = mDefaultFavicon;
+                image = mDefaultFaviconHelper.getDefaultFaviconDrawable(mActivity, url, true);
             }
         }
         viewHolder.imageView.setImageDrawable(image);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediator.java
index 2a0729f1..d41b30c7 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarMediator.java
@@ -44,9 +44,9 @@
     public UrlBarMediator(PropertyModel model) {
         mModel = model;
 
-        mModel.setValue(UrlBarProperties.FOCUS_CHANGE_CALLBACK, this::onUrlFocusChange);
-        mModel.setValue(UrlBarProperties.SHOW_CURSOR, false);
-        mModel.setValue(UrlBarProperties.TEXT_CONTEXT_MENU_DELEGATE, this);
+        mModel.set(UrlBarProperties.FOCUS_CHANGE_CALLBACK, this::onUrlFocusChange);
+        mModel.set(UrlBarProperties.SHOW_CURSOR, false);
+        mModel.set(UrlBarProperties.TEXT_CONTEXT_MENU_DELEGATE, this);
         setUseDarkTextColors(true);
     }
 
@@ -54,7 +54,7 @@
      * Set the primary delegate for the UrlBar view.
      */
     public void setDelegate(UrlBarDelegate delegate) {
-        mModel.setValue(UrlBarProperties.DELEGATE, delegate);
+        mModel.set(UrlBarProperties.DELEGATE, delegate);
     }
 
     /**
@@ -73,7 +73,7 @@
 
         // Do not scroll to the end of the host for URLs such as data:, javascript:, etc...
         if (data.url != null && data.originEndIndex == data.url.length()) {
-            Uri uri = Uri.parse(data.url.toString());
+            Uri uri = Uri.parse(data.url);
             String scheme = uri.getScheme();
             if (!TextUtils.isEmpty(scheme)
                     && UrlBarData.UNSUPPORTED_SCHEMES_TO_SPLIT.contains(scheme)) {
@@ -102,7 +102,7 @@
 
         UrlBarTextState state =
                 new UrlBarTextState(text, scrollType, mUrlBarData.originEndIndex, mSelectionState);
-        mModel.setValue(UrlBarProperties.TEXT_STATE, state);
+        mModel.set(UrlBarProperties.TEXT_STATE, state);
     }
 
     @VisibleForTesting
@@ -162,7 +162,7 @@
             assert false : "Should not update autocomplete text when not focused";
             return;
         }
-        mModel.setValue(UrlBarProperties.AUTOCOMPLETE_TEXT,
+        mModel.set(UrlBarProperties.AUTOCOMPLETE_TEXT,
                 new AutocompleteText(userText, autocompleteText));
     }
 
@@ -178,14 +178,14 @@
     private void onUrlFocusChange(boolean focus) {
         mHasFocus = focus;
 
-        if (mModel.getValue(UrlBarProperties.ALLOW_FOCUS)) {
-            mModel.setValue(UrlBarProperties.SHOW_CURSOR, mHasFocus);
+        if (mModel.get(UrlBarProperties.ALLOW_FOCUS)) {
+            mModel.set(UrlBarProperties.SHOW_CURSOR, mHasFocus);
         }
 
-        UrlBarTextState preCallbackState = mModel.getValue(UrlBarProperties.TEXT_STATE);
+        UrlBarTextState preCallbackState = mModel.get(UrlBarProperties.TEXT_STATE);
         if (mOnFocusChangeCallback != null) mOnFocusChangeCallback.onResult(focus);
         boolean textChangedInFocusCallback =
-                mModel.getValue(UrlBarProperties.TEXT_STATE) != preCallbackState;
+                mModel.get(UrlBarProperties.TEXT_STATE) != preCallbackState;
         if (mUrlBarData != null && !textChangedInFocusCallback) {
             pushTextToModel();
         }
@@ -197,8 +197,9 @@
      * @return Whether this resulted in a change from the previous value.
      */
     public boolean setUseDarkTextColors(boolean useDarkColors) {
-        boolean previousValue = mModel.getValue(UrlBarProperties.USE_DARK_TEXT_COLORS);
-        mModel.setValue(UrlBarProperties.USE_DARK_TEXT_COLORS, useDarkColors);
+        // TODO(bauerb): Make clients observe the property instead of checking the return value.
+        boolean previousValue = mModel.get(UrlBarProperties.USE_DARK_TEXT_COLORS);
+        mModel.set(UrlBarProperties.USE_DARK_TEXT_COLORS, useDarkColors);
         return previousValue != useDarkColors;
     }
 
@@ -206,9 +207,9 @@
      * Sets whether the view allows user focus.
      */
     public void setAllowFocus(boolean allowFocus) {
-        mModel.setValue(UrlBarProperties.ALLOW_FOCUS, allowFocus);
+        mModel.set(UrlBarProperties.ALLOW_FOCUS, allowFocus);
         if (allowFocus) {
-            mModel.setValue(UrlBarProperties.SHOW_CURSOR, mHasFocus);
+            mModel.set(UrlBarProperties.SHOW_CURSOR, mHasFocus);
         }
     }
 
@@ -216,21 +217,21 @@
      * Set the listener to be notified for URL direction changes.
      */
     public void setUrlDirectionListener(UrlDirectionListener listener) {
-        mModel.setValue(UrlBarProperties.URL_DIRECTION_LISTENER, listener);
+        mModel.set(UrlBarProperties.URL_DIRECTION_LISTENER, listener);
     }
 
     /**
      * Set the delegate that provides Window capabilities.
      */
     public void setWindowDelegate(WindowDelegate windowDelegate) {
-        mModel.setValue(UrlBarProperties.WINDOW_DELEGATE, windowDelegate);
+        mModel.set(UrlBarProperties.WINDOW_DELEGATE, windowDelegate);
     }
 
     /**
      * Set the callback to handle contextual Action Modes.
      */
     public void setActionModeCallback(ActionMode.Callback callback) {
-        mModel.setValue(UrlBarProperties.ACTION_MODE_CALLBACK, callback);
+        mModel.set(UrlBarProperties.ACTION_MODE_CALLBACK, callback);
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarViewBinder.java
index f0df4dd..d0300e3a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/UrlBarViewBinder.java
@@ -30,30 +30,29 @@
     public static void bind(PropertyModel model, UrlBar view, PropertyKey propertyKey) {
         if (UrlBarProperties.ACTION_MODE_CALLBACK.equals(propertyKey)) {
             view.setCustomSelectionActionModeCallback(
-                    model.getValue(UrlBarProperties.ACTION_MODE_CALLBACK));
+                    model.get(UrlBarProperties.ACTION_MODE_CALLBACK));
         } else if (UrlBarProperties.ALLOW_FOCUS.equals(propertyKey)) {
-            view.setAllowFocus(model.getValue(UrlBarProperties.ALLOW_FOCUS));
+            view.setAllowFocus(model.get(UrlBarProperties.ALLOW_FOCUS));
         } else if (UrlBarProperties.AUTOCOMPLETE_TEXT.equals(propertyKey)) {
-            AutocompleteText autocomplete = model.getValue(UrlBarProperties.AUTOCOMPLETE_TEXT);
+            AutocompleteText autocomplete = model.get(UrlBarProperties.AUTOCOMPLETE_TEXT);
             if (view.shouldAutocomplete()) {
                 view.setAutocompleteText(autocomplete.userText, autocomplete.autocompleteText);
             }
         } else if (UrlBarProperties.DELEGATE.equals(propertyKey)) {
-            view.setDelegate(model.getValue(UrlBarProperties.DELEGATE));
+            view.setDelegate(model.get(UrlBarProperties.DELEGATE));
         } else if (UrlBarProperties.FOCUS_CHANGE_CALLBACK.equals(propertyKey)) {
             final Callback<Boolean> focusChangeCallback =
-                    model.getValue(UrlBarProperties.FOCUS_CHANGE_CALLBACK);
+                    model.get(UrlBarProperties.FOCUS_CHANGE_CALLBACK);
             view.setOnFocusChangeListener((v, focused) -> {
                 if (focused) view.setIgnoreTextChangesForAutocomplete(false);
                 focusChangeCallback.onResult(focused);
             });
         } else if (UrlBarProperties.SHOW_CURSOR.equals(propertyKey)) {
-            view.setCursorVisible(model.getValue(UrlBarProperties.SHOW_CURSOR));
+            view.setCursorVisible(model.get(UrlBarProperties.SHOW_CURSOR));
         } else if (UrlBarProperties.TEXT_CONTEXT_MENU_DELEGATE.equals(propertyKey)) {
-            view.setTextContextMenuDelegate(
-                    model.getValue(UrlBarProperties.TEXT_CONTEXT_MENU_DELEGATE));
+            view.setTextContextMenuDelegate(model.get(UrlBarProperties.TEXT_CONTEXT_MENU_DELEGATE));
         } else if (UrlBarProperties.TEXT_STATE.equals(propertyKey)) {
-            UrlBarTextState state = model.getValue(UrlBarProperties.TEXT_STATE);
+            UrlBarTextState state = model.get(UrlBarProperties.TEXT_STATE);
             view.setIgnoreTextChangesForAutocomplete(true);
             view.setText(state.text);
             view.setScrollState(state.scrollType, state.scrollToIndex);
@@ -67,11 +66,11 @@
                 }
             }
         } else if (UrlBarProperties.USE_DARK_TEXT_COLORS.equals(propertyKey)) {
-            updateTextColors(view, model.getValue(UrlBarProperties.USE_DARK_TEXT_COLORS));
+            updateTextColors(view, model.get(UrlBarProperties.USE_DARK_TEXT_COLORS));
         } else if (UrlBarProperties.URL_DIRECTION_LISTENER.equals(propertyKey)) {
-            view.setUrlDirectionListener(model.getValue(UrlBarProperties.URL_DIRECTION_LISTENER));
+            view.setUrlDirectionListener(model.get(UrlBarProperties.URL_DIRECTION_LISTENER));
         } else if (UrlBarProperties.WINDOW_DELEGATE.equals(propertyKey)) {
-            view.setWindowDelegate(model.getValue(UrlBarProperties.WINDOW_DELEGATE));
+            view.setWindowDelegate(model.get(UrlBarProperties.WINDOW_DELEGATE));
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationDialogMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationDialogMediator.java
index 9e3d5a5..0cc1656 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationDialogMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationDialogMediator.java
@@ -11,9 +11,9 @@
     public static void initializeState(PasswordGenerationDialogModel model, String password,
             String saveExplanationText,
             Callback<Boolean> onPasswordAcceptedOrRejected) {
-        model.setValue(PasswordGenerationDialogModel.GENERATED_PASSWORD, password);
-        model.setValue(PasswordGenerationDialogModel.SAVE_EXPLANATION_TEXT, saveExplanationText);
-        model.setValue(PasswordGenerationDialogModel.PASSWORD_ACTION_CALLBACK,
+        model.set(PasswordGenerationDialogModel.GENERATED_PASSWORD, password);
+        model.set(PasswordGenerationDialogModel.SAVE_EXPLANATION_TEXT, saveExplanationText);
+        model.set(PasswordGenerationDialogModel.PASSWORD_ACTION_CALLBACK,
                 onPasswordAcceptedOrRejected);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationDialogViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationDialogViewBinder.java
index 1f356bbf..1d806fb 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationDialogViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/password_manager/PasswordGenerationDialogViewBinder.java
@@ -46,11 +46,11 @@
     public static void bind(
             PasswordGenerationDialogModel model, PasswordGenerationDialogViewHolder viewHolder) {
         viewHolder.setController(new PasswordGenerationDialogController(
-                model.getValue(PasswordGenerationDialogModel.PASSWORD_ACTION_CALLBACK)));
+                model.get(PasswordGenerationDialogModel.PASSWORD_ACTION_CALLBACK)));
         viewHolder.setGeneratedPassword(
-                model.getValue(PasswordGenerationDialogModel.GENERATED_PASSWORD));
+                model.get(PasswordGenerationDialogModel.GENERATED_PASSWORD));
         viewHolder.setSaveExplanationText(
-                model.getValue(PasswordGenerationDialogModel.SAVE_EXPLANATION_TEXT));
+                model.get(PasswordGenerationDialogModel.SAVE_EXPLANATION_TEXT));
         viewHolder.initializeView();
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java
index ce9263a..2bae25c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PrefServiceBridge.java
@@ -1044,6 +1044,21 @@
         nativeSetPromptForDownloadAndroid(status);
     }
 
+    /**
+     * @return Whether the explicit language prompt was shown at least once.
+     */
+    public boolean getExplicitLanguageAskPromptShown() {
+        return nativeGetExplicitLanguageAskPromptShown();
+    }
+
+    /**
+     * @param shown The value to set the underlying pref to: whether the prompt
+     * was shown to the user at least once.
+     */
+    public void setExplicitLanguageAskPromptShown(boolean shown) {
+        nativeSetExplicitLanguageAskPromptShown(shown);
+    }
+
     @VisibleForTesting
     public static void setInstanceForTesting(@Nullable PrefServiceBridge instanceForTesting) {
         sInstance = instanceForTesting;
@@ -1165,4 +1180,6 @@
     private native void nativeSetDownloadAndSaveFileDefaultDirectory(String directory);
     private native int nativeGetPromptForDownloadAndroid();
     private native void nativeSetPromptForDownloadAndroid(int status);
+    private native boolean nativeGetExplicitLanguageAskPromptShown();
+    private native void nativeSetExplicitLanguageAskPromptShown(boolean shown);
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferencesLauncher.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferencesLauncher.java
index d0c04ad..f2399d5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferencesLauncher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/PreferencesLauncher.java
@@ -10,7 +10,7 @@
 
 import org.chromium.base.ContextUtils;
 import org.chromium.base.annotations.CalledByNative;
-import org.chromium.chrome.browser.preferences.autofill.AutofillCreditCardsFragment;
+import org.chromium.chrome.browser.preferences.autofill.AutofillPaymentMethodsFragment;
 import org.chromium.chrome.browser.preferences.autofill.AutofillProfilesFragment;
 import org.chromium.chrome.browser.preferences.password.SavePasswordsPreferences;
 import org.chromium.chrome.browser.preferences.privacy.ClearBrowsingDataTabsFragment;
@@ -72,7 +72,7 @@
 
     @CalledByNative
     private static void showAutofillCreditCardSettings(WebContents webContents) {
-        showSettingSubpage(webContents, AutofillCreditCardsFragment.class.getName());
+        showSettingSubpage(webContents, AutofillPaymentMethodsFragment.class.getName());
     }
 
     @CalledByNative
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillAndPaymentsPreferences.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillAndPaymentsPreferences.java
index af0176da..f92aa26 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillAndPaymentsPreferences.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillAndPaymentsPreferences.java
@@ -9,17 +9,14 @@
 import android.preference.PreferenceFragment;
 
 import org.chromium.chrome.R;
-import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.autofill.PersonalDataManager;
-import org.chromium.chrome.browser.payments.AndroidPaymentAppFactory;
-import org.chromium.chrome.browser.payments.ServiceWorkerPaymentAppBridge;
 import org.chromium.chrome.browser.preferences.ChromeBasePreference;
 import org.chromium.chrome.browser.preferences.ManagedPreferenceDelegate;
 import org.chromium.chrome.browser.preferences.PreferenceUtils;
 
 /**
  * Autofill and payments settings fragment, which allows the user to edit autofill and credit card
- * profiles and control payment apps.
+ * profiles.
  */
 public class AutofillAndPaymentsPreferences extends PreferenceFragment {
     public static final String AUTOFILL_GUID = "guid";
@@ -29,7 +26,6 @@
     public static final String SETTINGS_ORIGIN = "Chrome settings";
     private static final String AUTOFILL_ADDRESSES = "autofill_addresses";
     private static final String AUTOFILL_PAYMENT_METHODS = "autofill_payment_methods";
-    private static final String PREF_PAYMENT_APPS = "payment_apps";
 
     private final ManagedPreferenceDelegate mManagedPreferenceDelegate;
 
@@ -43,16 +39,6 @@
         PreferenceUtils.addPreferencesFromResource(this, R.xml.autofill_and_payments_preferences);
         getActivity().setTitle(R.string.prefs_autofill_and_payments);
 
-        if (ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_PAYMENT_APPS)
-                || ChromeFeatureList.isEnabled(ChromeFeatureList.SERVICE_WORKER_PAYMENT_APPS)) {
-            Preference pref = new Preference(getActivity());
-            pref.setTitle(getActivity().getString(R.string.payment_apps_title));
-            pref.setFragment(AndroidPaymentAppsFragment.class.getCanonicalName());
-            pref.setShouldDisableView(true);
-            pref.setKey(PREF_PAYMENT_APPS);
-            getPreferenceScreen().addPreference(pref);
-        }
-
         ((ChromeBasePreference) findPreference(AUTOFILL_ADDRESSES))
                 .setManagedPreferenceDelegate(mManagedPreferenceDelegate);
         ((ChromeBasePreference) findPreference(AUTOFILL_PAYMENT_METHODS))
@@ -62,38 +48,6 @@
     @Override
     public void onResume() {
         super.onResume();
-        Preference pref = findPreference(PREF_PAYMENT_APPS);
-        if (pref != null) {
-            refreshPaymentAppsPrefForAndroidPaymentApps(pref);
-        }
-    }
-
-    private void refreshPaymentAppsPrefForAndroidPaymentApps(Preference pref) {
-        if (AndroidPaymentAppFactory.hasAndroidPaymentApps()) {
-            setPaymentAppsPrefStatus(pref, true);
-        } else {
-            refreshPaymentAppsPrefForServiceWorkerPaymentApps(pref);
-        }
-    }
-
-    private void refreshPaymentAppsPrefForServiceWorkerPaymentApps(Preference pref) {
-        ServiceWorkerPaymentAppBridge.hasServiceWorkerPaymentApps(
-                new ServiceWorkerPaymentAppBridge.HasServiceWorkerPaymentAppsCallback() {
-                    @Override
-                    public void onHasServiceWorkerPaymentAppsResponse(boolean hasPaymentApps) {
-                        setPaymentAppsPrefStatus(pref, hasPaymentApps);
-                    }
-                });
-    }
-
-    private void setPaymentAppsPrefStatus(Preference pref, boolean enabled) {
-        if (enabled) {
-            pref.setSummary(null);
-            pref.setEnabled(true);
-        } else {
-            pref.setSummary(getActivity().getString(R.string.payment_no_apps_summary));
-            pref.setEnabled(false);
-        }
     }
 
     ManagedPreferenceDelegate getManagedPreferenceDelegateForTest() {
@@ -119,6 +73,8 @@
                     return PersonalDataManager.isAutofillProfileManaged()
                             && !PersonalDataManager.isAutofillProfileEnabled();
                 }
+                // TODO(crbug.com/860526): Change this to allow access to payment apps even if cards
+                //                         autofill is disabled by policy.
                 if (AUTOFILL_PAYMENT_METHODS.equals(preference.getKey())) {
                     return PersonalDataManager.isAutofillCreditCardManaged()
                             && !PersonalDataManager.isAutofillCreditCardEnabled();
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillCreditCardsFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillCreditCardsFragment.java
deleted file mode 100644
index 00b3f43f..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillCreditCardsFragment.java
+++ /dev/null
@@ -1,117 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.preferences.autofill;
-
-import android.graphics.PorterDuff;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.preference.Preference;
-import android.preference.Preference.OnPreferenceChangeListener;
-import android.preference.PreferenceFragment;
-import android.support.v7.content.res.AppCompatResources;
-
-import org.chromium.base.ApiCompatibilityUtils;
-import org.chromium.chrome.R;
-import org.chromium.chrome.browser.autofill.PersonalDataManager;
-import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
-import org.chromium.chrome.browser.preferences.ChromeSwitchPreference;
-import org.chromium.chrome.browser.preferences.PreferenceUtils;
-
-/**
- * Autofill credit cards fragment, which allows the user to edit credit cards.
- */
-public class AutofillCreditCardsFragment
-        extends PreferenceFragment implements PersonalDataManager.PersonalDataManagerObserver {
-    private static final String PREF_AUTOFILL_ENABLE_CREDIT_CARDS_TOGGLE_LABEL =
-            "autofill_enable_credit_cards_toggle_label";
-
-    @Override
-    public void onCreate(Bundle savedInstanceState) {
-        super.onCreate(savedInstanceState);
-        PreferenceUtils.addPreferencesFromResource(
-                this, R.xml.autofill_and_payments_preference_fragment_screen);
-        getActivity().setTitle(R.string.autofill_payment_methods);
-    }
-
-    @Override
-    public void onResume() {
-        super.onResume();
-        // Always rebuild our list of credit cards.  Although we could detect if credit cards are
-        // added or deleted, the credit card summary (number) might be different.  To be safe, we
-        // update all.
-        rebuildCreditCardList();
-    }
-
-    private void rebuildCreditCardList() {
-        getPreferenceScreen().removeAll();
-        getPreferenceScreen().setOrderingAsAdded(true);
-
-        ChromeSwitchPreference autofillSwitch = new ChromeSwitchPreference(getActivity(), null);
-        autofillSwitch.setTitle(R.string.autofill_enable_credit_cards_toggle_label);
-        autofillSwitch.setSummary(
-                getActivity().getString(R.string.autofill_enable_credit_cards_toggle_sublabel));
-        autofillSwitch.setKey(PREF_AUTOFILL_ENABLE_CREDIT_CARDS_TOGGLE_LABEL); // For testing.
-        autofillSwitch.setChecked(PersonalDataManager.isAutofillCreditCardEnabled());
-        autofillSwitch.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
-            @Override
-            public boolean onPreferenceChange(Preference preference, Object newValue) {
-                PersonalDataManager.setAutofillCreditCardEnabled((boolean) newValue);
-                return true;
-            }
-        });
-        getPreferenceScreen().addPreference(autofillSwitch);
-
-        for (CreditCard card : PersonalDataManager.getInstance().getCreditCardsForSettings()) {
-            // Add a preference for the credit card.
-            Preference pref = new Preference(getActivity());
-            pref.setTitle(card.getObfuscatedNumber());
-            pref.setSummary(card.getFormattedExpirationDate(getActivity()));
-            pref.setIcon(
-                    AppCompatResources.getDrawable(getActivity(), card.getIssuerIconDrawableId()));
-
-            if (card.getIsLocal()) {
-                pref.setFragment(AutofillLocalCardEditor.class.getName());
-            } else {
-                pref.setFragment(AutofillServerCardEditor.class.getName());
-                pref.setWidgetLayoutResource(R.layout.autofill_server_data_label);
-            }
-
-            Bundle args = pref.getExtras();
-            args.putString(AutofillAndPaymentsPreferences.AUTOFILL_GUID, card.getGUID());
-            getPreferenceScreen().addPreference(pref);
-        }
-
-        // Add 'Add credit card' button. Tap of it brings up card editor which allows users type in
-        // new credit cards.
-        Preference pref = new Preference(getActivity());
-        Drawable plusIcon = ApiCompatibilityUtils.getDrawable(getResources(), R.drawable.plus);
-        plusIcon.mutate();
-        plusIcon.setColorFilter(
-                ApiCompatibilityUtils.getColor(getResources(), R.color.pref_accent_color),
-                PorterDuff.Mode.SRC_IN);
-        pref.setIcon(plusIcon);
-        pref.setTitle(R.string.autofill_create_credit_card);
-        pref.setFragment(AutofillLocalCardEditor.class.getName());
-        pref.setEnabled(PersonalDataManager.isAutofillCreditCardEnabled());
-        getPreferenceScreen().addPreference(pref);
-    }
-
-    @Override
-    public void onPersonalDataChanged() {
-        rebuildCreditCardList();
-    }
-
-    @Override
-    public void onActivityCreated(Bundle savedInstanceState) {
-        super.onActivityCreated(savedInstanceState);
-        PersonalDataManager.getInstance().registerDataObserver(this);
-    }
-
-    @Override
-    public void onDestroyView() {
-        PersonalDataManager.getInstance().unregisterDataObserver(this);
-        super.onDestroyView();
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillPaymentMethodsFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillPaymentMethodsFragment.java
new file mode 100644
index 0000000..e148288
--- /dev/null
+++ b/chrome/android/java/src/org/chromium/chrome/browser/preferences/autofill/AutofillPaymentMethodsFragment.java
@@ -0,0 +1,163 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.preferences.autofill;
+
+import android.graphics.PorterDuff;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.preference.Preference;
+import android.preference.Preference.OnPreferenceChangeListener;
+import android.preference.PreferenceFragment;
+import android.support.v7.content.res.AppCompatResources;
+
+import org.chromium.base.ApiCompatibilityUtils;
+import org.chromium.chrome.R;
+import org.chromium.chrome.browser.ChromeFeatureList;
+import org.chromium.chrome.browser.autofill.PersonalDataManager;
+import org.chromium.chrome.browser.autofill.PersonalDataManager.CreditCard;
+import org.chromium.chrome.browser.payments.AndroidPaymentAppFactory;
+import org.chromium.chrome.browser.payments.ServiceWorkerPaymentAppBridge;
+import org.chromium.chrome.browser.preferences.ChromeSwitchPreference;
+import org.chromium.chrome.browser.preferences.PreferenceUtils;
+
+/**
+ * Autofill credit cards fragment, which allows the user to edit credit cards and control
+ * payment apps.
+ */
+public class AutofillPaymentMethodsFragment
+        extends PreferenceFragment implements PersonalDataManager.PersonalDataManagerObserver {
+    private static final String PREF_AUTOFILL_ENABLE_CREDIT_CARDS_TOGGLE_LABEL =
+            "autofill_enable_credit_cards_toggle_label";
+
+    private static final String PREF_PAYMENT_APPS = "payment_apps";
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        PreferenceUtils.addPreferencesFromResource(
+                this, R.xml.autofill_and_payments_preference_fragment_screen);
+        getActivity().setTitle(R.string.autofill_payment_methods);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        // Always rebuild our list of credit cards.  Although we could detect if credit cards are
+        // added or deleted, the credit card summary (number) might be different.  To be safe, we
+        // update all.
+        rebuildPage();
+    }
+
+    private void rebuildPage() {
+        getPreferenceScreen().removeAll();
+        getPreferenceScreen().setOrderingAsAdded(true);
+
+        ChromeSwitchPreference autofillSwitch = new ChromeSwitchPreference(getActivity(), null);
+        autofillSwitch.setTitle(R.string.autofill_enable_credit_cards_toggle_label);
+        autofillSwitch.setSummary(
+                getActivity().getString(R.string.autofill_enable_credit_cards_toggle_sublabel));
+        autofillSwitch.setKey(PREF_AUTOFILL_ENABLE_CREDIT_CARDS_TOGGLE_LABEL); // For testing.
+        autofillSwitch.setChecked(PersonalDataManager.isAutofillCreditCardEnabled());
+        autofillSwitch.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
+            @Override
+            public boolean onPreferenceChange(Preference preference, Object newValue) {
+                PersonalDataManager.setAutofillCreditCardEnabled((boolean) newValue);
+                return true;
+            }
+        });
+        getPreferenceScreen().addPreference(autofillSwitch);
+
+        for (CreditCard card : PersonalDataManager.getInstance().getCreditCardsForSettings()) {
+            // Add a preference for the credit card.
+            Preference card_pref = new Preference(getActivity());
+            card_pref.setTitle(card.getObfuscatedNumber());
+            card_pref.setSummary(card.getFormattedExpirationDate(getActivity()));
+            card_pref.setIcon(
+                    AppCompatResources.getDrawable(getActivity(), card.getIssuerIconDrawableId()));
+
+            if (card.getIsLocal()) {
+                card_pref.setFragment(AutofillLocalCardEditor.class.getName());
+            } else {
+                card_pref.setFragment(AutofillServerCardEditor.class.getName());
+                card_pref.setWidgetLayoutResource(R.layout.autofill_server_data_label);
+            }
+
+            Bundle args = card_pref.getExtras();
+            args.putString(AutofillAndPaymentsPreferences.AUTOFILL_GUID, card.getGUID());
+            getPreferenceScreen().addPreference(card_pref);
+        }
+
+        // Add 'Add credit card' button. Tap of it brings up card editor which allows users type in
+        // new credit cards.
+        Preference add_card_pref = new Preference(getActivity());
+        Drawable plusIcon = ApiCompatibilityUtils.getDrawable(getResources(), R.drawable.plus);
+        plusIcon.mutate();
+        plusIcon.setColorFilter(
+                ApiCompatibilityUtils.getColor(getResources(), R.color.pref_accent_color),
+                PorterDuff.Mode.SRC_IN);
+        add_card_pref.setIcon(plusIcon);
+        add_card_pref.setTitle(R.string.autofill_create_credit_card);
+        add_card_pref.setFragment(AutofillLocalCardEditor.class.getName());
+        add_card_pref.setEnabled(PersonalDataManager.isAutofillCreditCardEnabled());
+        getPreferenceScreen().addPreference(add_card_pref);
+
+        // Add the link to payment apps only after the credit card list is rebuilt.
+        if (ChromeFeatureList.isEnabled(ChromeFeatureList.ANDROID_PAYMENT_APPS)
+                || ChromeFeatureList.isEnabled(ChromeFeatureList.SERVICE_WORKER_PAYMENT_APPS)) {
+            Preference payment_apps_pref = new Preference(getActivity());
+            payment_apps_pref.setTitle(getActivity().getString(R.string.payment_apps_title));
+            payment_apps_pref.setFragment(AndroidPaymentAppsFragment.class.getCanonicalName());
+            payment_apps_pref.setShouldDisableView(true);
+            payment_apps_pref.setKey(PREF_PAYMENT_APPS);
+            getPreferenceScreen().addPreference(payment_apps_pref);
+            refreshPaymentAppsPrefForAndroidPaymentApps(payment_apps_pref);
+        }
+    }
+
+    private void refreshPaymentAppsPrefForAndroidPaymentApps(Preference pref) {
+        if (AndroidPaymentAppFactory.hasAndroidPaymentApps()) {
+            setPaymentAppsPrefStatus(pref, true);
+        } else {
+            refreshPaymentAppsPrefForServiceWorkerPaymentApps(pref);
+        }
+    }
+
+    private void refreshPaymentAppsPrefForServiceWorkerPaymentApps(Preference pref) {
+        ServiceWorkerPaymentAppBridge.hasServiceWorkerPaymentApps(
+                new ServiceWorkerPaymentAppBridge.HasServiceWorkerPaymentAppsCallback() {
+                    @Override
+                    public void onHasServiceWorkerPaymentAppsResponse(boolean hasPaymentApps) {
+                        setPaymentAppsPrefStatus(pref, hasPaymentApps);
+                    }
+                });
+    }
+
+    private void setPaymentAppsPrefStatus(Preference pref, boolean enabled) {
+        if (enabled) {
+            pref.setSummary(null);
+            pref.setEnabled(true);
+        } else {
+            pref.setSummary(getActivity().getString(R.string.payment_no_apps_summary));
+            pref.setEnabled(false);
+        }
+    }
+
+    @Override
+    public void onPersonalDataChanged() {
+        rebuildPage();
+    }
+
+    @Override
+    public void onActivityCreated(Bundle savedInstanceState) {
+        super.onActivityCreated(savedInstanceState);
+        PersonalDataManager.getInstance().registerDataObserver(this);
+    }
+
+    @Override
+    public void onDestroyView() {
+        PersonalDataManager.getInstance().unregisterDataObserver(this);
+        super.onDestroyView();
+    }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarMediator.java
index 8a470db..899a7d5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarMediator.java
@@ -79,19 +79,17 @@
         mFirstSlotData = firstSlotData;
         mSecondSlotData = secondSlotData;
 
-        mModel.setValue(BottomToolbarModel.PRIMARY_COLOR, primaryColor);
+        mModel.set(BottomToolbarModel.PRIMARY_COLOR, primaryColor);
 
-        mModel.setValue(
-                BottomToolbarModel.FIRST_BUTTON_DATA, mFirstSlotData.browsingModeButtonData);
-        mModel.setValue(
-                BottomToolbarModel.SECOND_BUTTON_DATA, mSecondSlotData.browsingModeButtonData);
+        mModel.set(BottomToolbarModel.FIRST_BUTTON_DATA, mFirstSlotData.browsingModeButtonData);
+        mModel.set(BottomToolbarModel.SECOND_BUTTON_DATA, mSecondSlotData.browsingModeButtonData);
     }
 
     /**
      * @param swipeHandler The handler that controls the toolbar swipe behavior.
      */
     void setToolbarSwipeHandler(EdgeSwipeHandler swipeHandler) {
-        mModel.setValue(BottomToolbarModel.TOOLBAR_SWIPE_HANDLER, swipeHandler);
+        mModel.set(BottomToolbarModel.TOOLBAR_SWIPE_HANDLER, swipeHandler);
     }
 
     /**
@@ -101,8 +99,8 @@
         mFullscreenManager.removeListener(this);
         if (mOverviewModeBehavior != null) mOverviewModeBehavior.removeOverviewModeObserver(this);
         if (mWindowAndroid != null) mWindowAndroid.removeKeyboardVisibilityListener(this);
-        if (mModel.getValue(BottomToolbarModel.LAYOUT_MANAGER) != null) {
-            LayoutManager manager = mModel.getValue(BottomToolbarModel.LAYOUT_MANAGER);
+        if (mModel.get(BottomToolbarModel.LAYOUT_MANAGER) != null) {
+            LayoutManager manager = mModel.get(BottomToolbarModel.LAYOUT_MANAGER);
             manager.getOverlayPanelManager().removeObserver(this);
             manager.removeSceneChangeObserver(this);
         }
@@ -113,9 +111,9 @@
 
     @Override
     public void onControlsOffsetChanged(float topOffset, float bottomOffset, boolean needsAnimate) {
-        mModel.setValue(BottomToolbarModel.Y_OFFSET, (int) bottomOffset);
+        mModel.set(BottomToolbarModel.Y_OFFSET, (int) bottomOffset);
         if (bottomOffset > 0 || mFullscreenManager.getBottomControlsHeight() == 0) {
-            mModel.setValue(BottomToolbarModel.ANDROID_VIEW_VISIBLE, false);
+            mModel.set(BottomToolbarModel.ANDROID_VIEW_VISIBLE, false);
         } else {
             tryShowingAndroidView();
         }
@@ -129,9 +127,8 @@
 
     @Override
     public void onOverviewModeStartedShowing(boolean showToolbar) {
-        mModel.setValue(
-                BottomToolbarModel.FIRST_BUTTON_DATA, mFirstSlotData.tabSwitcherModeButtonData);
-        mModel.setValue(
+        mModel.set(BottomToolbarModel.FIRST_BUTTON_DATA, mFirstSlotData.tabSwitcherModeButtonData);
+        mModel.set(
                 BottomToolbarModel.SECOND_BUTTON_DATA, mSecondSlotData.tabSwitcherModeButtonData);
     }
 
@@ -140,10 +137,8 @@
 
     @Override
     public void onOverviewModeStartedHiding(boolean showToolbar, boolean delayAnimation) {
-        mModel.setValue(
-                BottomToolbarModel.FIRST_BUTTON_DATA, mFirstSlotData.browsingModeButtonData);
-        mModel.setValue(
-                BottomToolbarModel.SECOND_BUTTON_DATA, mSecondSlotData.browsingModeButtonData);
+        mModel.set(BottomToolbarModel.FIRST_BUTTON_DATA, mFirstSlotData.browsingModeButtonData);
+        mModel.set(BottomToolbarModel.SECOND_BUTTON_DATA, mSecondSlotData.browsingModeButtonData);
     }
 
     @Override
@@ -151,7 +146,7 @@
 
     @Override
     public void onOverlayPanelShown() {
-        mModel.setValue(BottomToolbarModel.ANDROID_VIEW_VISIBLE, false);
+        mModel.set(BottomToolbarModel.ANDROID_VIEW_VISIBLE, false);
     }
 
     @Override
@@ -165,15 +160,15 @@
         // the bottom toolbar view to visible or invisible regardless of the previous state.
         if (isShowing) {
             mBottomToolbarHeightBeforeHide = mFullscreenManager.getBottomControlsHeight();
-            mModel.setValue(BottomToolbarModel.ANDROID_VIEW_VISIBLE, false);
-            mModel.setValue(BottomToolbarModel.COMPOSITED_VIEW_VISIBLE, false);
+            mModel.set(BottomToolbarModel.ANDROID_VIEW_VISIBLE, false);
+            mModel.set(BottomToolbarModel.COMPOSITED_VIEW_VISIBLE, false);
             mFullscreenManager.setBottomControlsHeight(0);
         } else {
             mFullscreenManager.setBottomControlsHeight(mBottomToolbarHeightBeforeHide);
             tryShowingAndroidView();
-            mModel.setValue(
+            mModel.set(
                     BottomToolbarModel.Y_OFFSET, (int) mFullscreenManager.getBottomControlOffset());
-            mModel.setValue(BottomToolbarModel.COMPOSITED_VIEW_VISIBLE, true);
+            mModel.set(BottomToolbarModel.COMPOSITED_VIEW_VISIBLE, true);
         }
     }
 
@@ -184,12 +179,12 @@
      */
     private void tryShowingAndroidView() {
         if (mFullscreenManager.getBottomControlOffset() > 0) return;
-        if (mModel.getValue(BottomToolbarModel.Y_OFFSET) != 0) return;
-        mModel.setValue(BottomToolbarModel.ANDROID_VIEW_VISIBLE, true);
+        if (mModel.get(BottomToolbarModel.Y_OFFSET) != 0) return;
+        mModel.set(BottomToolbarModel.ANDROID_VIEW_VISIBLE, true);
     }
 
     void setLayoutManager(LayoutManager layoutManager) {
-        mModel.setValue(BottomToolbarModel.LAYOUT_MANAGER, layoutManager);
+        mModel.set(BottomToolbarModel.LAYOUT_MANAGER, layoutManager);
         layoutManager.addSceneChangeObserver(this);
         layoutManager.getOverlayPanelManager().addObserver(this);
     }
@@ -201,16 +196,16 @@
     public void onSceneChange(Layout layout) {
         if (layout instanceof ToolbarSwipeLayout) {
             mIsInSwipeLayout = true;
-            mModel.setValue(BottomToolbarModel.ANDROID_VIEW_VISIBLE, false);
+            mModel.set(BottomToolbarModel.ANDROID_VIEW_VISIBLE, false);
         } else if (mIsInSwipeLayout) {
             // Only change to visible if leaving the swipe layout.
             mIsInSwipeLayout = false;
-            mModel.setValue(BottomToolbarModel.ANDROID_VIEW_VISIBLE, true);
+            mModel.set(BottomToolbarModel.ANDROID_VIEW_VISIBLE, true);
         }
     }
 
     void setResourceManager(ResourceManager resourceManager) {
-        mModel.setValue(BottomToolbarModel.RESOURCE_MANAGER, resourceManager);
+        mModel.set(BottomToolbarModel.RESOURCE_MANAGER, resourceManager);
     }
 
     void setOverviewModeBehavior(OverviewModeBehavior overviewModeBehavior) {
@@ -219,7 +214,7 @@
     }
 
     void setToolbarSwipeLayout(ToolbarSwipeLayout layout) {
-        mModel.setValue(BottomToolbarModel.TOOLBAR_SWIPE_LAYOUT, layout);
+        mModel.set(BottomToolbarModel.TOOLBAR_SWIPE_LAYOUT, layout);
     }
 
     void setWindowAndroid(WindowAndroid windowAndroid) {
@@ -235,14 +230,14 @@
         mSecondSlotData.tabSwitcherModeButtonData = secondSlotButtonData;
 
         if (mOverviewModeBehavior.overviewVisible()) {
-            mModel.setValue(
+            mModel.set(
                     BottomToolbarModel.FIRST_BUTTON_DATA, mFirstSlotData.tabSwitcherModeButtonData);
-            mModel.setValue(BottomToolbarModel.SECOND_BUTTON_DATA,
+            mModel.set(BottomToolbarModel.SECOND_BUTTON_DATA,
                     mSecondSlotData.tabSwitcherModeButtonData);
         }
     }
 
     void setPrimaryColor(int color) {
-        mModel.setValue(BottomToolbarModel.PRIMARY_COLOR, color);
+        mModel.set(BottomToolbarModel.PRIMARY_COLOR, color);
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarViewBinder.java
index 00ecf1b..bdceb17 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/BottomToolbarViewBinder.java
@@ -60,48 +60,45 @@
     public final void bind(BottomToolbarModel model, ViewHolder view, PropertyKey propertyKey) {
         if (BottomToolbarModel.Y_OFFSET == propertyKey) {
             assert view.sceneLayer != null;
-            view.sceneLayer.setYOffset(model.getValue(BottomToolbarModel.Y_OFFSET));
+            view.sceneLayer.setYOffset(model.get(BottomToolbarModel.Y_OFFSET));
         } else if (BottomToolbarModel.ANDROID_VIEW_VISIBLE == propertyKey) {
-            view.toolbarRoot.setVisibility(model.getValue(BottomToolbarModel.ANDROID_VIEW_VISIBLE)
+            view.toolbarRoot.setVisibility(model.get(BottomToolbarModel.ANDROID_VIEW_VISIBLE)
                             ? View.VISIBLE
                             : View.INVISIBLE);
         } else if (BottomToolbarModel.COMPOSITED_VIEW_VISIBLE == propertyKey) {
-            view.sceneLayer.setIsVisible(
-                    model.getValue(BottomToolbarModel.COMPOSITED_VIEW_VISIBLE));
-            model.getValue(BottomToolbarModel.LAYOUT_MANAGER).requestUpdate();
+            view.sceneLayer.setIsVisible(model.get(BottomToolbarModel.COMPOSITED_VIEW_VISIBLE));
+            model.get(BottomToolbarModel.LAYOUT_MANAGER).requestUpdate();
         } else if (BottomToolbarModel.LAYOUT_MANAGER == propertyKey) {
             assert view.sceneLayer == null;
             view.sceneLayer = new ScrollingBottomViewSceneLayer(
                     view.toolbarRoot, view.toolbarRoot.getTopShadowHeight());
-            model.getValue(BottomToolbarModel.LAYOUT_MANAGER)
-                    .addSceneOverlayToBack(view.sceneLayer);
+            model.get(BottomToolbarModel.LAYOUT_MANAGER).addSceneOverlayToBack(view.sceneLayer);
         } else if (BottomToolbarModel.TOOLBAR_SWIPE_LAYOUT == propertyKey) {
             assert view.sceneLayer != null;
-            model.getValue(BottomToolbarModel.TOOLBAR_SWIPE_LAYOUT)
+            model.get(BottomToolbarModel.TOOLBAR_SWIPE_LAYOUT)
                     .setBottomToolbarSceneLayers(new ScrollingBottomViewSceneLayer(view.sceneLayer),
                             new ScrollingBottomViewSceneLayer(view.sceneLayer));
         } else if (BottomToolbarModel.RESOURCE_MANAGER == propertyKey) {
-            model.getValue(BottomToolbarModel.RESOURCE_MANAGER)
+            model.get(BottomToolbarModel.RESOURCE_MANAGER)
                     .getDynamicResourceLoader()
                     .registerResource(
                             view.toolbarRoot.getId(), view.toolbarRoot.getResourceAdapter());
         } else if (BottomToolbarModel.TOOLBAR_SWIPE_HANDLER == propertyKey) {
-            view.toolbarRoot.setSwipeDetector(
-                    model.getValue(BottomToolbarModel.TOOLBAR_SWIPE_HANDLER));
+            view.toolbarRoot.setSwipeDetector(model.get(BottomToolbarModel.TOOLBAR_SWIPE_HANDLER));
         } else if (BottomToolbarModel.FIRST_BUTTON_DATA == propertyKey) {
             updateButton(view.firstTintedImageButton,
-                    model.getValue(BottomToolbarModel.FIRST_BUTTON_DATA), useLightIcons(model));
+                    model.get(BottomToolbarModel.FIRST_BUTTON_DATA), useLightIcons(model));
         } else if (BottomToolbarModel.SECOND_BUTTON_DATA == propertyKey) {
             updateButton(view.secondTintedImageButton,
-                    model.getValue(BottomToolbarModel.SECOND_BUTTON_DATA), useLightIcons(model));
+                    model.get(BottomToolbarModel.SECOND_BUTTON_DATA), useLightIcons(model));
         } else if (BottomToolbarModel.PRIMARY_COLOR == propertyKey) {
             final boolean useLightIcons = useLightIcons(model);
             view.toolbarRoot.findViewById(R.id.bottom_sheet_toolbar)
-                    .setBackgroundColor(model.getValue(BottomToolbarModel.PRIMARY_COLOR));
+                    .setBackgroundColor(model.get(BottomToolbarModel.PRIMARY_COLOR));
             updateButtonDrawable(view.firstTintedImageButton,
-                    model.getValue(BottomToolbarModel.FIRST_BUTTON_DATA), useLightIcons);
+                    model.get(BottomToolbarModel.FIRST_BUTTON_DATA), useLightIcons);
             updateButtonDrawable(view.secondTintedImageButton,
-                    model.getValue(BottomToolbarModel.SECOND_BUTTON_DATA), useLightIcons);
+                    model.get(BottomToolbarModel.SECOND_BUTTON_DATA), useLightIcons);
         } else {
             assert false : "Unhandled property detected in BottomToolbarViewBinder!";
         }
@@ -109,7 +106,7 @@
 
     private static boolean useLightIcons(BottomToolbarModel model) {
         return ColorUtils.shouldUseLightForegroundOnBackground(
-                model.getValue(BottomToolbarModel.PRIMARY_COLOR));
+                model.get(BottomToolbarModel.PRIMARY_COLOR));
     }
 
     private static void updateButton(
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/TabSwitcherButtonCoordinator.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/TabSwitcherButtonCoordinator.java
index f4bd7a0..ef9e45b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/TabSwitcherButtonCoordinator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/TabSwitcherButtonCoordinator.java
@@ -49,7 +49,7 @@
                 mTabSwitcherButtonModel, view, new TabSwitcherButtonViewBinder());
 
         CharSequence description = root.getResources().getString(R.string.open_tabs);
-        mTabSwitcherButtonModel.setValue(TabSwitcherButtonProperties.ON_LONG_CLICK_LISTENER,
+        mTabSwitcherButtonModel.set(TabSwitcherButtonProperties.ON_LONG_CLICK_LISTENER,
                 v -> AccessibilityUtil.showAccessibilityToast(root.getContext(), v, description));
     }
 
@@ -58,8 +58,7 @@
      *                        button is clicked.
      */
     public void setTabSwitcherListener(OnClickListener onClickListener) {
-        mTabSwitcherButtonModel.setValue(
-                TabSwitcherButtonProperties.ON_CLICK_LISTENER, onClickListener);
+        mTabSwitcherButtonModel.set(TabSwitcherButtonProperties.ON_CLICK_LISTENER, onClickListener);
     }
 
     /**
@@ -121,7 +120,7 @@
      * @param tint The {@link ColorStateList} used to tint the button.
      */
     public void setTint(ColorStateList tint) {
-        mTabSwitcherButtonModel.setValue(TabSwitcherButtonProperties.TINT, tint);
+        mTabSwitcherButtonModel.set(TabSwitcherButtonProperties.TINT, tint);
     }
 
     public void destroy() {
@@ -130,7 +129,7 @@
     }
 
     private void updateTabCount() {
-        mTabSwitcherButtonModel.setValue(TabSwitcherButtonProperties.NUMBER_OF_TABS,
+        mTabSwitcherButtonModel.set(TabSwitcherButtonProperties.NUMBER_OF_TABS,
                 mTabModelSelector.getCurrentModel().getCount());
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/TabSwitcherButtonViewBinder.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/TabSwitcherButtonViewBinder.java
index 3fef53d5..208b744b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/TabSwitcherButtonViewBinder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/TabSwitcherButtonViewBinder.java
@@ -26,14 +26,14 @@
     public final void bind(
             PropertyModel model, TabSwitcherButtonView view, PropertyKey propertyKey) {
         if (TabSwitcherButtonProperties.NUMBER_OF_TABS == propertyKey) {
-            view.updateTabCountVisuals(model.getValue(TabSwitcherButtonProperties.NUMBER_OF_TABS));
+            view.updateTabCountVisuals(model.get(TabSwitcherButtonProperties.NUMBER_OF_TABS));
         } else if (TabSwitcherButtonProperties.ON_CLICK_LISTENER == propertyKey) {
-            view.setOnClickListener(model.getValue(TabSwitcherButtonProperties.ON_CLICK_LISTENER));
+            view.setOnClickListener(model.get(TabSwitcherButtonProperties.ON_CLICK_LISTENER));
         } else if (TabSwitcherButtonProperties.ON_LONG_CLICK_LISTENER == propertyKey) {
             view.setOnLongClickListener(
-                    model.getValue(TabSwitcherButtonProperties.ON_LONG_CLICK_LISTENER));
+                    model.get(TabSwitcherButtonProperties.ON_LONG_CLICK_LISTENER));
         } else if (TabSwitcherButtonProperties.TINT == propertyKey) {
-            view.setTint(model.getValue(TabSwitcherButtonProperties.TINT));
+            view.setTint(model.get(TabSwitcherButtonProperties.TINT));
         } else {
             assert false : "Unhandled property detected in TabSwitcherViewBinder!";
         }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonSlotData.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonSlotData.java
index 0b4f2e57..ef6fe29 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonSlotData.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarButtonSlotData.java
@@ -110,7 +110,7 @@
 
                 @Override
                 public void onAnimationEnd(Animator animator) {
-                    if (mDrawable == null) imageButton.setEnabled(false);
+                    imageButton.setEnabled(mDrawable != null);
                     imageButton.setOnClickListener(mOnClickListener);
                 }
             });
diff --git a/chrome/android/java/strings/android_chrome_strings.grd b/chrome/android/java/strings/android_chrome_strings.grd
index 75e3017f..9ed68a25 100644
--- a/chrome/android/java/strings/android_chrome_strings.grd
+++ b/chrome/android/java/strings/android_chrome_strings.grd
@@ -415,7 +415,7 @@
 
       <!-- Autofill and Payments preferences -->
       <message name="IDS_AUTOFILL_KEYBOARD_ACCESSORY_CONTENT_DESCRIPTION" desc="The text announced by the screen reader when the autofill suggestions are shown.">
-        Suggestions available
+        Passwords available
       </message>
       <message name="IDS_PREFS_AUTOFILL_AND_PAYMENTS" desc="Title of Autofill and payments settings prefrences. [CHAR-LIMIT=32]">
         Autofill and payments
@@ -3695,6 +3695,9 @@
       </message>
 
       <!-- Password Accessory Strings -->
+      <message name="IDS_KEYBOARD_ACCESSORY_SHEET_HIDE" desc="Description for the active icon button that closes an accessory sheet and brings back the keyboard.">
+          Show keyboard
+      </message>
       <message name="IDS_PASSWORD_GENERATION_ACCESSORY_BUTTON" desc="Text for the button used to generate a password.">
           Suggest strong password...
       </message>
@@ -3702,7 +3705,10 @@
           Suggest password...
       </message>
       <message name="IDS_PASSWORD_ACCESSORY_SHEET_TOGGLE" desc="Description for the icon button used to open and close the password accessory sheet.">
-          Tap to toggle between password suggestions and keyboard
+          Show passwords
+      </message>
+      <message name="IDS_PASSWORD_ACCESSORY_SHEET_OPENED" desc="Accessibility announcement when opening a password bottom sheet containing saved credentials and options like managing and generating passwords.">
+          Showing saved passwords and password options
       </message>
 
 
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_AUTOFILL_KEYBOARD_ACCESSORY_CONTENT_DESCRIPTION.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_AUTOFILL_KEYBOARD_ACCESSORY_CONTENT_DESCRIPTION.png.sha1
new file mode 100644
index 0000000..080b50a
--- /dev/null
+++ b/chrome/android/java/strings/android_chrome_strings_grd/IDS_AUTOFILL_KEYBOARD_ACCESSORY_CONTENT_DESCRIPTION.png.sha1
@@ -0,0 +1 @@
+8510ce9350a385eb899a54c907bf433be107578a
\ No newline at end of file
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_KEYBOARD_ACCESSORY_SHEET_HIDE.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_KEYBOARD_ACCESSORY_SHEET_HIDE.png.sha1
new file mode 100644
index 0000000..1ae896b
--- /dev/null
+++ b/chrome/android/java/strings/android_chrome_strings_grd/IDS_KEYBOARD_ACCESSORY_SHEET_HIDE.png.sha1
@@ -0,0 +1 @@
+9fc70d018187ef3aabde44d211768026d9732221
\ No newline at end of file
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_PASSWORD_ACCESSORY_SHEET_OPENED.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_PASSWORD_ACCESSORY_SHEET_OPENED.png.sha1
new file mode 100644
index 0000000..b2d2362
--- /dev/null
+++ b/chrome/android/java/strings/android_chrome_strings_grd/IDS_PASSWORD_ACCESSORY_SHEET_OPENED.png.sha1
@@ -0,0 +1 @@
+c87e7ab32ece2c4980afcdde5eebc1ed53bcd81e
\ No newline at end of file
diff --git a/chrome/android/java/strings/android_chrome_strings_grd/IDS_PASSWORD_ACCESSORY_SHEET_TOGGLE.png.sha1 b/chrome/android/java/strings/android_chrome_strings_grd/IDS_PASSWORD_ACCESSORY_SHEET_TOGGLE.png.sha1
index 28ad997..3c76b01 100644
--- a/chrome/android/java/strings/android_chrome_strings_grd/IDS_PASSWORD_ACCESSORY_SHEET_TOGGLE.png.sha1
+++ b/chrome/android/java/strings/android_chrome_strings_grd/IDS_PASSWORD_ACCESSORY_SHEET_TOGGLE.png.sha1
@@ -1 +1 @@
-5716c5bb3e618d7064c16d47d34c06437a21276d
\ No newline at end of file
+b48ecba6a01f55383fbc161d5be48453d57ff016
\ No newline at end of file
diff --git a/chrome/android/java_sources.gni b/chrome/android/java_sources.gni
index 3c2e083..e24bb04 100644
--- a/chrome/android/java_sources.gni
+++ b/chrome/android/java_sources.gni
@@ -1172,7 +1172,7 @@
   "java/src/org/chromium/chrome/browser/preferences/autofill/AndroidPaymentAppPreference.java",
   "java/src/org/chromium/chrome/browser/preferences/autofill/AndroidPaymentAppsFragment.java",
   "java/src/org/chromium/chrome/browser/preferences/autofill/AutofillAndPaymentsPreferences.java",
-  "java/src/org/chromium/chrome/browser/preferences/autofill/AutofillCreditCardsFragment.java",
+  "java/src/org/chromium/chrome/browser/preferences/autofill/AutofillPaymentMethodsFragment.java",
   "java/src/org/chromium/chrome/browser/preferences/autofill/AutofillCreditCardEditor.java",
   "java/src/org/chromium/chrome/browser/preferences/autofill/AutofillEditorBase.java",
   "java/src/org/chromium/chrome/browser/preferences/autofill/AutofillLocalCardEditor.java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/MediaLauncherActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/MediaLauncherActivityTest.java
index 5b60ce2..eb9fb3b 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/MediaLauncherActivityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/media/MediaLauncherActivityTest.java
@@ -24,7 +24,7 @@
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.browser.ChromeSwitches;
-import org.chromium.chrome.browser.customtabs.CustomTabActivity;
+import org.chromium.chrome.browser.customtabs.SeparateTaskCustomTabActivity;
 import org.chromium.chrome.browser.customtabs.SeparateTaskCustomTabActivity0;
 import org.chromium.chrome.browser.tab.Tab;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
@@ -122,10 +122,10 @@
 
     private void waitForCustomTabActivityToStart(Callable<Void> trigger, String expectedUrl)
             throws Exception {
-        CustomTabActivity cta;
+        SeparateTaskCustomTabActivity cta;
         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
-            cta = ActivityUtils.waitForActivity(
-                    InstrumentationRegistry.getInstrumentation(), CustomTabActivity.class, trigger);
+            cta = ActivityUtils.waitForActivity(InstrumentationRegistry.getInstrumentation(),
+                    SeparateTaskCustomTabActivity.class, trigger);
         } else {
             cta = ActivityUtils.waitForActivity(InstrumentationRegistry.getInstrumentation(),
                     SeparateTaskCustomTabActivity0.class, trigger);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/modelutil/LazyConstructionPropertyMcpTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/modelutil/LazyConstructionPropertyMcpTest.java
index a04c94a..110edbe 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/modelutil/LazyConstructionPropertyMcpTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/modelutil/LazyConstructionPropertyMcpTest.java
@@ -57,6 +57,7 @@
     public void setup() {
         MockitoAnnotations.initMocks(this);
         mModel = new PropertyModel(ALL_PROPERTIES);
+        mModel.set(VISIBILITY, false);
         mViewProvider = new FakeViewProvider<>();
         mModel.addObserver((source, propertyKey) -> {
             // Forward model changes to the model observer if it exists. It's important for the test
@@ -70,7 +71,7 @@
         LazyConstructionPropertyMcp.create(mModel, VISIBILITY, mViewProvider, mViewBinder);
         assertFalse(mViewProvider.inflationHasStarted());
 
-        mModel.setValue(VISIBILITY, true);
+        mModel.set(VISIBILITY, true);
 
         assertTrue(mViewProvider.inflationHasStarted());
         mViewProvider.finishInflation(mView);
@@ -82,8 +83,8 @@
     @Test
     public void testUpdatesBeforeInflation() {
         LazyConstructionPropertyMcp.create(mModel, VISIBILITY, mViewProvider, mViewBinder);
-        mModel.setValue(STRING_PROPERTY, "foo");
-        mModel.setValue(VISIBILITY, true);
+        mModel.set(STRING_PROPERTY, "foo");
+        mModel.set(VISIBILITY, true);
         assertTrue(mViewProvider.inflationHasStarted());
         mViewProvider.finishInflation(mView);
         ShadowLooper.idleMainLooper();
@@ -95,17 +96,17 @@
         LazyConstructionPropertyMcp.create(mModel, VISIBILITY, mViewProvider, mViewBinder);
 
         // Show the view and pump the looper to do the initial bind.
-        mModel.setValue(VISIBILITY, true);
+        mModel.set(VISIBILITY, true);
         assertTrue(mViewProvider.inflationHasStarted());
         mViewProvider.finishInflation(mView);
         ShadowLooper.idleMainLooper();
         verifyBind(VISIBILITY);
         Mockito.<ViewBinder>reset(mViewBinder);
 
-        mModel.setValue(INT_PROPERTY, 42);
+        mModel.set(INT_PROPERTY, 42);
         verifyBind(INT_PROPERTY);
 
-        mModel.setValue(VISIBILITY, false);
+        mModel.set(VISIBILITY, false);
         verifyBind(VISIBILITY);
     }
 
@@ -114,48 +115,49 @@
         LazyConstructionPropertyMcp.create(mModel, VISIBILITY, mViewProvider, mViewBinder);
 
         // Show the view and pump the looper to do the initial bind, then hide the view again.
-        mModel.setValue(VISIBILITY, true);
+        mModel.set(VISIBILITY, true);
         assertTrue(mViewProvider.inflationHasStarted());
         mViewProvider.finishInflation(mView);
         ShadowLooper.idleMainLooper();
         verifyBind(VISIBILITY);
 
-        mModel.setValue(VISIBILITY, false);
+        mModel.set(VISIBILITY, false);
         verify(mViewBinder, times(2)).bind(eq(mModel), eq(mView), eq(VISIBILITY));
         Mockito.<ViewBinder>reset(mViewBinder);
 
         // While the view is hidden, the binder should not be invoked.
-        mModel.setValue(STRING_PROPERTY, "foo");
-        mModel.setValue(STRING_PROPERTY, "bar");
+        mModel.set(STRING_PROPERTY, "foo");
+        mModel.set(STRING_PROPERTY, "bar");
         verify(mViewBinder, never())
                 .bind(any(PropertyModel.class), any(View.class), any(PropertyKey.class));
 
         // When the view is shown, all pending updates should be dispatched, coalescing updates to
         // the same property.
-        mModel.setValue(VISIBILITY, true);
+        mModel.set(VISIBILITY, true);
         verifyBind(VISIBILITY, STRING_PROPERTY);
     }
 
     @Test
     public void testReentrantUpdates() {
+        mModel.set(INT_PROPERTY, 0);
         LazyConstructionPropertyMcp.create(mModel, VISIBILITY, mViewProvider, mViewBinder);
 
         // Increase INT_PROPERTY any time visibility changes.
         mModelObserver = (source, propertyKey) -> {
             if (propertyKey != VISIBILITY) return;
-            mModel.setValue(INT_PROPERTY, mModel.getValue(INT_PROPERTY) + 1);
+            mModel.set(INT_PROPERTY, mModel.get(INT_PROPERTY) + 1);
         };
 
-        mModel.setValue(VISIBILITY, true);
+        mModel.set(VISIBILITY, true);
         mViewProvider.finishInflation(mView);
         ShadowLooper.idleMainLooper();
         verifyBind(VISIBILITY, INT_PROPERTY);
-        assertThat(mModel.getValue(INT_PROPERTY), is(1));
+        assertThat(mModel.get(INT_PROPERTY), is(1));
         Mockito.<ViewBinder>reset(mViewBinder);
 
-        mModel.setValue(VISIBILITY, false);
+        mModel.set(VISIBILITY, false);
         verifyBind(INT_PROPERTY, VISIBILITY);
-        assertThat(mModel.getValue(INT_PROPERTY), is(2));
+        assertThat(mModel.get(INT_PROPERTY), is(2));
     }
 
     private void verifyBind(PropertyKey... properties) {
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/modelutil/PropertyModelTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/modelutil/PropertyModelTest.java
index b525de63..731f6ff9 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/modelutil/PropertyModelTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/modelutil/PropertyModelTest.java
@@ -53,22 +53,11 @@
     public static ObjectPropertyKey<List<Integer>> OBJECT_PROPERTY_C = new ObjectPropertyKey<>();
 
     @Test
-    public void defaultValues() {
-        PropertyModel model = new PropertyModel(
-                BOOLEAN_PROPERTY_A, FLOAT_PROPERTY_A, INT_PROPERTY_A, OBJECT_PROPERTY_A);
-
-        assertThat(model.getValue(BOOLEAN_PROPERTY_A), equalTo(false));
-        assertThat(model.getValue(FLOAT_PROPERTY_A), equalTo(0f));
-        assertThat(model.getValue(INT_PROPERTY_A), equalTo(0));
-        assertThat(model.getValue(OBJECT_PROPERTY_A), equalTo(null));
-    }
-
-    @Test
     public void getAllSetProperties() {
         PropertyModel model = new PropertyModel(
                 BOOLEAN_PROPERTY_A, FLOAT_PROPERTY_A, INT_PROPERTY_A, OBJECT_PROPERTY_A);
-        model.setValue(BOOLEAN_PROPERTY_A, true);
-        model.setValue(INT_PROPERTY_A, 42);
+        model.set(BOOLEAN_PROPERTY_A, true);
+        model.set(INT_PROPERTY_A, 42);
         Collection<PropertyKey> setProperties = model.getAllSetProperties();
         assertThat(setProperties, containsInAnyOrder(BOOLEAN_PROPERTY_A, INT_PROPERTY_A));
         assertThat(setProperties.size(), equalTo(2));
@@ -90,9 +79,9 @@
         model.addObserver(observer);
         Mockito.<PropertyObserver>reset(observer);
 
-        model.setValue(key, value);
+        model.set(key, value);
         verify(observer).onPropertyChanged(model, key);
-        assertThat(model.getValue(key), equalTo(value));
+        assertThat(model.get(key), equalTo(value));
 
         model.removeObserver(observer);
     }
@@ -119,9 +108,9 @@
         model.addObserver(observer);
         Mockito.<PropertyObserver>reset(observer);
 
-        model.setValue(key, value);
+        model.set(key, value);
         verify(observer).onPropertyChanged(model, key);
-        assertThat(model.getValue(key), equalTo(value));
+        assertThat(model.get(key), equalTo(value));
 
         model.removeObserver(observer);
     }
@@ -144,9 +133,9 @@
         model.addObserver(observer);
         Mockito.<PropertyObserver>reset(observer);
 
-        model.setValue(key, value);
+        model.set(key, value);
         verify(observer).onPropertyChanged(model, key);
-        assertThat(model.getValue(key), equalTo(value));
+        assertThat(model.get(key), equalTo(value));
 
         model.removeObserver(observer);
     }
@@ -180,9 +169,9 @@
         model.addObserver(observer);
         Mockito.<PropertyObserver>reset(observer);
 
-        model.setValue(key, value);
+        model.set(key, value);
         verify(observer).onPropertyChanged(model, key);
-        assertThat(model.getValue(key), equalTo(value));
+        assertThat(model.get(key), equalTo(value));
 
         model.removeObserver(observer);
     }
@@ -191,22 +180,22 @@
     public void duplicateSetChangeSuppression() {
         PropertyModel model = new PropertyModel(
                 BOOLEAN_PROPERTY_A, FLOAT_PROPERTY_A, INT_PROPERTY_A, OBJECT_PROPERTY_A);
-        model.setValue(BOOLEAN_PROPERTY_A, true);
-        model.setValue(FLOAT_PROPERTY_A, 1f);
-        model.setValue(INT_PROPERTY_A, -1);
+        model.set(BOOLEAN_PROPERTY_A, true);
+        model.set(FLOAT_PROPERTY_A, 1f);
+        model.set(INT_PROPERTY_A, -1);
 
         Object obj = new Object();
-        model.setValue(OBJECT_PROPERTY_A, obj);
+        model.set(OBJECT_PROPERTY_A, obj);
 
         @SuppressWarnings("unchecked")
         PropertyObserver<PropertyKey> observer = Mockito.mock(PropertyObserver.class);
         model.addObserver(observer);
         Mockito.<PropertyObserver>reset(observer);
 
-        model.setValue(BOOLEAN_PROPERTY_A, true);
-        model.setValue(FLOAT_PROPERTY_A, 1f);
-        model.setValue(INT_PROPERTY_A, -1);
-        model.setValue(OBJECT_PROPERTY_A, obj);
+        model.set(BOOLEAN_PROPERTY_A, true);
+        model.set(FLOAT_PROPERTY_A, 1f);
+        model.set(INT_PROPERTY_A, -1);
+        model.set(OBJECT_PROPERTY_A, obj);
 
         Mockito.verifyZeroInteractions(observer);
     }
@@ -215,7 +204,7 @@
     public void ensureValidKey() {
         PropertyModel model = new PropertyModel(BOOLEAN_PROPERTY_A, BOOLEAN_PROPERTY_B);
         thrown.expect(IllegalArgumentException.class);
-        model.setValue(BOOLEAN_PROPERTY_C, true);
+        model.set(BOOLEAN_PROPERTY_C, true);
     }
 
     @Test(expected = IllegalArgumentException.class)
diff --git a/chrome/app/nibs/BUILD.gn b/chrome/app/nibs/BUILD.gn
index b310bf7..b262dc2c 100644
--- a/chrome/app/nibs/BUILD.gn
+++ b/chrome/app/nibs/BUILD.gn
@@ -18,10 +18,6 @@
   "Toolbar.xib",
 ]
 
-if (!mac_views_browser) {
-  translated_xibs += [ "HttpAuthLoginSheet.xib" ]
-}
-
 untranslated_xibs = [
   "BookmarkBarFolderWindow.xib",
   "FindBar.xib",
diff --git a/chrome/app/nibs/HttpAuthLoginSheet.xib b/chrome/app/nibs/HttpAuthLoginSheet.xib
deleted file mode 100644
index 28862ed..0000000
--- a/chrome/app/nibs/HttpAuthLoginSheet.xib
+++ /dev/null
@@ -1,172 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5056" systemVersion="13F34" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
-    <dependencies>
-        <deployment version="1090" identifier="macosx"/>
-        <development version="5100" identifier="xcode"/>
-        <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="5056"/>
-    </dependencies>
-    <objects>
-        <customObject id="-2" userLabel="File's Owner" customClass="LoginHandlerSheet">
-            <connections>
-                <outlet property="cancelButton_" destination="13" id="47"/>
-                <outlet property="authorityField_" destination="53" id="52"/>
-                <outlet property="explanationField_" destination="41" id="45"/>
-                <outlet property="loginButton_" destination="11" id="46"/>
-                <outlet property="nameField_" destination="7" id="21"/>
-                <outlet property="passwordField_" destination="9" id="22"/>
-                <outlet property="window" destination="1" id="23"/>
-            </connections>
-        </customObject>
-        <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
-        <customObject id="-3" userLabel="Application"/>
-        <window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" visibleAtLaunch="NO" animationBehavior="default" id="1" customClass="ConstrainedWindowCustomWindow">
-            <windowPositionMask key="initialPositionMask" leftStrut="YES" bottomStrut="YES"/>
-            <rect key="contentRect" x="196" y="388" width="400" height="234"/>
-            <rect key="screenRect" x="0.0" y="0.0" width="1440" height="878"/>
-            <view key="contentView" id="2" customClass="ConstrainedWindowCustomWindowContentView">
-                <rect key="frame" x="0.0" y="-5" width="400" height="234"/>
-                <autoresizingMask key="autoresizingMask"/>
-                <subviews>
-                    <box autoresizesSubviews="NO" transparent="YES" borderType="none" titlePosition="noTitle" id="24">
-                        <rect key="frame" x="105" y="70" width="283" height="74"/>
-                        <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
-                        <view key="contentView">
-                            <rect key="frame" x="0.0" y="0.0" width="283" height="74"/>
-                            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
-                            <subviews>
-                                <secureTextField verticalHuggingPriority="750" id="9">
-                                    <rect key="frame" x="6" y="10" width="269" height="22"/>
-                                    <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
-                                    <secureTextFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="10">
-                                        <font key="font" metaFont="system"/>
-                                        <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
-                                        <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
-                                        <allowedInputSourceLocales>
-                                            <string>NSAllRomanInputSourcesLocaleIdentifier</string>
-                                        </allowedInputSourceLocales>
-                                    </secureTextFieldCell>
-                                    <connections>
-                                        <outlet property="nextKeyView" destination="7" id="egd-qv-hFh"/>
-                                    </connections>
-                                </secureTextField>
-                                <textField verticalHuggingPriority="750" id="7">
-                                    <rect key="frame" x="6" y="42" width="269" height="22"/>
-                                    <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
-                                    <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" drawsBackground="YES" id="8">
-                                        <font key="font" metaFont="system"/>
-                                        <color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
-                                        <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
-                                    </textFieldCell>
-                                    <connections>
-                                        <outlet property="nextKeyView" destination="9" id="UlM-bu-LpF"/>
-                                    </connections>
-                                </textField>
-                            </subviews>
-                        </view>
-                        <color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/>
-                        <color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
-                    </box>
-                    <customView id="33" customClass="GTMWidthBasedTweaker">
-                        <rect key="frame" x="168" y="20" width="231" height="52"/>
-                        <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
-                        <subviews>
-                            <button verticalHuggingPriority="750" id="13" customClass="ConstrainedWindowButton">
-                                <rect key="frame" x="10" y="12" width="96" height="32"/>
-                                <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
-                                <buttonCell key="cell" type="push" title="^IDS_CANCEL" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="14" customClass="ConstrainedWindowButtonCell">
-                                    <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                                    <font key="font" metaFont="system"/>
-                                    <string key="keyEquivalent" base64-UTF8="YES">
-Gw
-</string>
-                                </buttonCell>
-                                <connections>
-                                    <action selector="cancelPressed:" target="-2" id="20"/>
-                                </connections>
-                            </button>
-                            <button verticalHuggingPriority="750" id="11" customClass="ConstrainedWindowButton">
-                                <rect key="frame" x="116" y="12" width="96" height="32"/>
-                                <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
-                                <buttonCell key="cell" type="push" title="^IDS_LOGIN_DIALOG_OK_BUTTON_LABEL" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="12" customClass="ConstrainedWindowButtonCell">
-                                    <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
-                                    <font key="font" metaFont="system"/>
-                                    <string key="keyEquivalent" base64-UTF8="YES">
-DQ
-</string>
-                                </buttonCell>
-                                <connections>
-                                    <action selector="loginPressed:" target="-2" id="19"/>
-                                </connections>
-                            </button>
-                        </subviews>
-                    </customView>
-                    <customView id="34" customClass="GTMWidthBasedTweaker">
-                        <rect key="frame" x="20" y="74" width="89" height="68"/>
-                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
-                        <subviews>
-                            <textField verticalHuggingPriority="750" id="5">
-                                <rect key="frame" x="-3" y="8" width="86" height="17"/>
-                                <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
-                                <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="^IDS_LOGIN_DIALOG_PASSWORD_FIELD" id="6">
-                                    <font key="font" metaFont="cellTitle"/>
-                                    <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
-                                    <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
-                                </textFieldCell>
-                            </textField>
-                            <textField verticalHuggingPriority="750" id="3">
-                                <rect key="frame" x="-3" y="40" width="86" height="17"/>
-                                <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
-                                <textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="^IDS_LOGIN_DIALOG_USERNAME_FIELD" id="4">
-                                    <font key="font" metaFont="cellTitle"/>
-                                    <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
-                                    <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
-                                </textFieldCell>
-                            </textField>
-                        </subviews>
-                        <connections>
-                            <outlet property="viewToResize_" destination="1" id="39"/>
-                            <outlet property="viewToSlideAndResize_" destination="24" id="40"/>
-                        </connections>
-                    </customView>
-                    <textField verticalHuggingPriority="750" id="41">
-                        <rect key="frame" x="18" y="151" width="365" height="17"/>
-                        <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
-                        <textFieldCell key="cell" sendsActionOnEndEditing="YES" title="explanation" id="42">
-                            <font key="font" metaFont="cellTitle"/>
-                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
-                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
-                        </textFieldCell>
-                    </textField>
-                    <textField verticalHuggingPriority="750" id="53">
-                        <rect key="frame" x="19" y="176" width="365" height="17"/>
-                        <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
-                        <textFieldCell key="cell" sendsActionOnEndEditing="YES" title="authority" id="54">
-                            <font key="font" metaFont="cellTitle"/>
-                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
-                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
-                        </textFieldCell>
-                    </textField>
-                    <textField verticalHuggingPriority="750" id="50">
-                        <rect key="frame" x="17" y="201" width="353" height="19"/>
-                        <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
-                        <textFieldCell key="cell" sendsActionOnEndEditing="YES" title="^IDS_LOGIN_DIALOG_TITLE" id="51">
-                            <font key="font" metaFont="system" size="15"/>
-                            <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
-                            <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
-                        </textFieldCell>
-                    </textField>
-                </subviews>
-            </view>
-            <connections>
-                <outlet property="initialFirstResponder" destination="7" id="56"/>
-            </connections>
-        </window>
-        <customObject id="35" customClass="GTMUILocalizerAndLayoutTweaker">
-            <connections>
-                <outlet property="localizer_" destination="36" id="48"/>
-                <outlet property="uiObject_" destination="1" id="49"/>
-            </connections>
-        </customObject>
-        <customObject id="36" customClass="ChromeUILocalizer"/>
-    </objects>
-</document>
diff --git a/chrome/app/settings_strings.grdp b/chrome/app/settings_strings.grdp
index 77e7afc6..74ef777 100644
--- a/chrome/app/settings_strings.grdp
+++ b/chrome/app/settings_strings.grdp
@@ -3617,10 +3617,10 @@
   <message name="IDS_SETTINGS_PASSPHRASE_EXPLANATION_TEXT" desc="Message shown when explicit passphrase is selected.">
     Only someone with your passphrase can read your encrypted data. The passphrase is not sent to or stored by Google. If you forget your passphrase or want to change this setting, you'll need to <ph name="BEGIN_LINK">&lt;a href="$1" target=&quot;_blank&quot;&gt;<ex>&lt;a href="$1" target=&quot;_blank&quot;&gt;</ex></ph>reset sync<ph name="END_LINK">&lt;/a&gt;<ex>&lt;/a&gt;</ex></ph>.
   </message>
-  <message name="IDS_SETTINGS_PASSPHRASE_RESET_HINT" desc="Informs user how to change their encryption setting.">
-    To change this setting, <ph name="BEGIN_LINK">&lt;a href="$1" target=&quot;_blank&quot;&gt;<ex>&lt;a href="$1" target=&quot;_blank&quot;&gt;</ex></ph>reset sync<ph name="END_LINK">&lt;/a&gt;<ex>&lt;/a&gt;</ex></ph>.
+  <message name="IDS_SETTINGS_PASSPHRASE_RESET_HINT_ENCRYPTION" desc="Informs user how to change their encryption setting.">
+    To change this setting, <ph name="BEGIN_LINK">&lt;a href="$1" target=&quot;_blank&quot;&gt;<ex>&lt;a href="$1" target=&quot;_blank&quot;&gt;</ex></ph>reset sync<ph name="END_LINK">&lt;/a&gt;<ex>&lt;/a&gt;</ex></ph> to remove your sync passphrase
   </message>
-  <message name="IDS_SETTINGS_PASSPHRASE_RESET_HINT_UNIFIED_CONSENT" desc="Informs user how to change their encryption setting when unified consent is enabled.">
+  <message name="IDS_SETTINGS_PASSPHRASE_RESET_HINT_TOGGLE" desc="Informs user how to change their encryption setting when unified consent is enabled.">
     To turn this on, <ph name="BEGIN_LINK">&lt;a href="$1" target=&quot;_blank&quot;&gt;<ex>&lt;a href="$1" target=&quot;_blank&quot;&gt;</ex></ph>reset sync<ph name="END_LINK">&lt;/a&gt;<ex>&lt;/a&gt;</ex></ph> to remove your sync passphrase
   </message>
   <message name="IDS_SETTINGS_EMPTY_PASSPHRASE_ERROR" desc="Error message when the passphrase is empty.">
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index e349a159..0c9ba88 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -5099,13 +5099,6 @@
     deps += [ "//chromeos:test_support" ]
   }
 
-  if (is_mac && !mac_views_browser) {
-    sources += [
-      "chooser_controller/mock_chooser_controller.cc",
-      "chooser_controller/mock_chooser_controller.h",
-    ]
-  }
-
   if (is_win) {
     sources += [
       "notifications/win/mock_itoastnotification.cc",
diff --git a/chrome/browser/android/feed/feed_offline_bridge.cc b/chrome/browser/android/feed/feed_offline_bridge.cc
index 9b2224d7..62911262 100644
--- a/chrome/browser/android/feed/feed_offline_bridge.cc
+++ b/chrome/browser/android/feed/feed_offline_bridge.cc
@@ -32,7 +32,7 @@
 namespace {
 
 void OnGetOfflineStatus(ScopedJavaGlobalRef<jobject> callback,
-                        const std::vector<std::string>& urls) {
+                        std::vector<std::string> urls) {
   JNIEnv* env = base::android::AttachCurrentThread();
   ScopedJavaLocalRef<jobjectArray> j_urls =
       base::android::ToJavaArrayOfStrings(env, urls);
@@ -82,7 +82,7 @@
   base::android::AppendJavaStringArrayToStringVector(env, j_urls.obj(), &urls);
   ScopedJavaGlobalRef<jobject> callback(j_callback);
   offline_host_->GetOfflineStatus(
-      urls, base::BindOnce(&OnGetOfflineStatus, callback));
+      std::move(urls), base::BindOnce(&OnGetOfflineStatus, callback));
 }
 
 void FeedOfflineBridge::OnContentRemoved(
diff --git a/chrome/browser/android/metrics/uma_utils.cc b/chrome/browser/android/metrics/uma_utils.cc
index eeba416..cca27c3 100644
--- a/chrome/browser/android/metrics/uma_utils.cc
+++ b/chrome/browser/android/metrics/uma_utils.cc
@@ -41,5 +41,10 @@
                           : metrics::EnableMetricsDefault::OPT_OUT);
 }
 
+void SetUsageAndCrashReporting(bool enabled) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  Java_UmaUtils_setUsageAndCrashReportingFromNative(env, enabled);
+}
+
 }  // namespace android
 }  // namespace chrome
diff --git a/chrome/browser/android/metrics/uma_utils.h b/chrome/browser/android/metrics/uma_utils.h
index b52b1c2..7822aea7 100644
--- a/chrome/browser/android/metrics/uma_utils.h
+++ b/chrome/browser/android/metrics/uma_utils.h
@@ -14,6 +14,10 @@
 
 base::TimeTicks GetMainEntryPointTimeTicks();
 
+// Sets whether UMA reporting is enabled. This will call to Java to update
+// the shared preference that is the source of truth for UMA reporting.
+void SetUsageAndCrashReporting(bool enabled);
+
 }  // namespace android
 }  // namespace chrome
 
diff --git a/chrome/browser/android/preferences/pref_service_bridge.cc b/chrome/browser/android/preferences/pref_service_bridge.cc
index 2eb37668c..b508972 100644
--- a/chrome/browser/android/preferences/pref_service_bridge.cc
+++ b/chrome/browser/android/preferences/pref_service_bridge.cc
@@ -1330,6 +1330,23 @@
   GetPrefService()->SetInteger(prefs::kPromptForDownloadAndroid, status);
 }
 
+static jboolean JNI_PrefServiceBridge_GetExplicitLanguageAskPromptShown(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
+  std::unique_ptr<translate::TranslatePrefs> translate_prefs =
+      ChromeTranslateClient::CreateTranslatePrefs(GetPrefService());
+  return translate_prefs->GetExplicitLanguageAskPromptShown();
+}
+
+static void JNI_PrefServiceBridge_SetExplicitLanguageAskPromptShown(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    jboolean shown) {
+  std::unique_ptr<translate::TranslatePrefs> translate_prefs =
+      ChromeTranslateClient::CreateTranslatePrefs(GetPrefService());
+  translate_prefs->SetExplicitLanguageAskPromptShown(shown);
+}
+
 const char* PrefServiceBridge::GetPrefNameExposedToJava(int pref_index) {
   DCHECK_GE(pref_index, 0);
   DCHECK_LT(pref_index, Pref::PREF_NUM_PREFS);
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
index 6f46e2c..56026fe 100644
--- a/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
+++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.cc
@@ -418,6 +418,7 @@
 void BackgroundFetchDelegateImpl::OnDownloadSucceeded(
     const std::string& download_guid,
     const base::FilePath& path,
+    base::Optional<storage::BlobDataHandle> blob_handle,
     uint64_t size) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
 
@@ -438,7 +439,7 @@
     client()->OnDownloadComplete(
         job_unique_id, download_guid,
         std::make_unique<content::BackgroundFetchResult>(
-            base::Time::Now(), path, base::nullopt /* blob_handle */, size));
+            base::Time::Now(), path, std::move(blob_handle), size));
   }
 
   job_details.current_download_guids.erase(
diff --git a/chrome/browser/background_fetch/background_fetch_delegate_impl.h b/chrome/browser/background_fetch/background_fetch_delegate_impl.h
index 299470fa..85561d5 100644
--- a/chrome/browser/background_fetch/background_fetch_delegate_impl.h
+++ b/chrome/browser/background_fetch/background_fetch_delegate_impl.h
@@ -31,6 +31,10 @@
 class OfflineContentAggregator;
 }  // namespace offline_items_collection
 
+namespace storage {
+class BlobDataHandle;
+}  // namespace storage
+
 // Implementation of BackgroundFetchDelegate using the DownloadService. This
 // also implements OfflineContentProvider which allows it to show notifications
 // for its downloads.
@@ -83,6 +87,7 @@
 
   void OnDownloadSucceeded(const std::string& guid,
                            const base::FilePath& path,
+                           base::Optional<storage::BlobDataHandle> blob_handle,
                            uint64_t size);
 
   // OfflineContentProvider implementation:
diff --git a/chrome/browser/background_fetch/background_fetch_download_client.cc b/chrome/browser/background_fetch/background_fetch_download_client.cc
index 1a51bf60..2ccbc997 100644
--- a/chrome/browser/background_fetch/background_fetch_download_client.cc
+++ b/chrome/browser/background_fetch/background_fetch_download_client.cc
@@ -77,7 +77,8 @@
     const std::string& guid,
     const download::CompletionInfo& info) {
   if (delegate_)
-    delegate_->OnDownloadSucceeded(guid, info.path, info.bytes_downloaded);
+    delegate_->OnDownloadSucceeded(guid, info.path, info.blob_handle,
+                                   info.bytes_downloaded);
 }
 
 bool BackgroundFetchDownloadClient::CanServiceRemoveDownloadedFile(
diff --git a/chrome/browser/chooser_controller/mock_chooser_controller.cc b/chrome/browser/chooser_controller/mock_chooser_controller.cc
deleted file mode 100644
index 92fc1e1..0000000
--- a/chrome/browser/chooser_controller/mock_chooser_controller.cc
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/chooser_controller/mock_chooser_controller.h"
-
-#include <algorithm>
-
-#include "base/logging.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/grit/generated_resources.h"
-#include "ui/base/l10n/l10n_util.h"
-
-MockChooserController::MockChooserController()
-    : ChooserController(nullptr,
-                        IDS_USB_DEVICE_CHOOSER_PROMPT_ORIGIN,
-                        IDS_USB_DEVICE_CHOOSER_PROMPT_EXTENSION_NAME) {
-  set_title_for_testing(base::ASCIIToUTF16("Mock Chooser Dialog"));
-}
-
-MockChooserController::~MockChooserController() {}
-
-bool MockChooserController::ShouldShowIconBeforeText() const {
-  return true;
-}
-
-base::string16 MockChooserController::GetNoOptionsText() const {
-  return l10n_util::GetStringUTF16(IDS_DEVICE_CHOOSER_NO_DEVICES_FOUND_PROMPT);
-}
-
-base::string16 MockChooserController::GetOkButtonLabel() const {
-  return l10n_util::GetStringUTF16(IDS_USB_DEVICE_CHOOSER_CONNECT_BUTTON_TEXT);
-}
-
-size_t MockChooserController::NumOptions() const {
-  return options_.size();
-}
-
-int MockChooserController::GetSignalStrengthLevel(size_t index) const {
-  return options_[index].signal_strength_level;
-}
-
-base::string16 MockChooserController::GetOption(size_t index) const {
-  return options_[index].name;
-}
-
-bool MockChooserController::IsConnected(size_t index) const {
-  return options_[index].connected_paired_status &
-         ConnectedPairedStatus::CONNECTED;
-}
-
-bool MockChooserController::IsPaired(size_t index) const {
-  return options_[index].connected_paired_status &
-         ConnectedPairedStatus::PAIRED;
-}
-
-base::string16 MockChooserController::GetStatus() const {
-  return status_text_;
-}
-
-void MockChooserController::OnAdapterPresenceChanged(
-    content::BluetoothChooser::AdapterPresence presence) {
-  ClearAllOptions();
-  switch (presence) {
-    case content::BluetoothChooser::AdapterPresence::ABSENT:
-      NOTREACHED();
-      break;
-    case content::BluetoothChooser::AdapterPresence::POWERED_OFF:
-      status_text_ = base::string16();
-      if (view())
-        view()->OnAdapterEnabledChanged(false /* Adapter is turned off */);
-      break;
-    case content::BluetoothChooser::AdapterPresence::POWERED_ON:
-      status_text_ =
-          l10n_util::GetStringUTF16(IDS_BLUETOOTH_DEVICE_CHOOSER_RE_SCAN);
-      if (view())
-        view()->OnAdapterEnabledChanged(true /* Adapter is turned on */);
-      break;
-  }
-}
-
-void MockChooserController::OnDiscoveryStateChanged(
-    content::BluetoothChooser::DiscoveryState state) {
-  switch (state) {
-    case content::BluetoothChooser::DiscoveryState::DISCOVERING:
-      ClearAllOptions();
-      status_text_ =
-          l10n_util::GetStringUTF16(IDS_BLUETOOTH_DEVICE_CHOOSER_SCANNING);
-      if (view()) {
-        view()->OnRefreshStateChanged(
-            true /* Refreshing options is in progress */);
-      }
-      break;
-    case content::BluetoothChooser::DiscoveryState::IDLE:
-    case content::BluetoothChooser::DiscoveryState::FAILED_TO_START:
-      status_text_ =
-          l10n_util::GetStringUTF16(IDS_BLUETOOTH_DEVICE_CHOOSER_RE_SCAN);
-      if (view()) {
-        view()->OnRefreshStateChanged(
-            false /* Refreshing options is complete */);
-      }
-      break;
-  }
-}
-
-void MockChooserController::OptionAdded(const base::string16& option_name,
-                                        int signal_strength_level,
-                                        int connected_paired_status) {
-  options_.push_back(
-      {option_name, signal_strength_level, connected_paired_status});
-  if (view())
-    view()->OnOptionAdded(options_.size() - 1);
-}
-
-void MockChooserController::OptionRemoved(const base::string16& option_name) {
-  auto it = std::find_if(options_.begin(), options_.end(),
-                         [&option_name](const OptionInfo& option) {
-                           return option.name == option_name;
-                         });
-
-  if (it != options_.end()) {
-    size_t index = it - options_.begin();
-    options_.erase(it);
-    if (view())
-      view()->OnOptionRemoved(index);
-  }
-}
-
-void MockChooserController::OptionUpdated(
-    const base::string16& previous_option_name,
-    const base::string16& new_option_name,
-    int new_signal_strength_level,
-    int new_connected_paired_status) {
-  auto it = std::find_if(options_.begin(), options_.end(),
-                         [&previous_option_name](const OptionInfo& option) {
-                           return option.name == previous_option_name;
-                         });
-
-  if (it != options_.end()) {
-    *it = {new_option_name, new_signal_strength_level,
-           new_connected_paired_status};
-    if (view())
-      view()->OnOptionUpdated(it - options_.begin());
-  }
-}
-
-const int MockChooserController::kNoSignalStrengthLevelImage = -1;
-const int MockChooserController::kSignalStrengthLevel0Bar = 0;
-const int MockChooserController::kSignalStrengthLevel1Bar = 1;
-const int MockChooserController::kSignalStrengthLevel2Bar = 2;
-const int MockChooserController::kSignalStrengthLevel3Bar = 3;
-const int MockChooserController::kSignalStrengthLevel4Bar = 4;
-const int MockChooserController::kImageColorUnselected = 0;
-const int MockChooserController::kImageColorSelected = 1;
-
-void MockChooserController::ClearAllOptions() {
-  options_.clear();
-}
diff --git a/chrome/browser/chooser_controller/mock_chooser_controller.h b/chrome/browser/chooser_controller/mock_chooser_controller.h
deleted file mode 100644
index dfb9024..0000000
--- a/chrome/browser/chooser_controller/mock_chooser_controller.h
+++ /dev/null
@@ -1,82 +0,0 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_CHOOSER_CONTROLLER_MOCK_CHOOSER_CONTROLLER_H_
-#define CHROME_BROWSER_CHOOSER_CONTROLLER_MOCK_CHOOSER_CONTROLLER_H_
-
-#include <vector>
-
-#include "base/macros.h"
-#include "chrome/browser/chooser_controller/chooser_controller.h"
-#include "content/public/browser/bluetooth_chooser.h"
-#include "testing/gmock/include/gmock/gmock.h"
-
-// Deprecated. Use FakeBluetoothChooserController instead.
-class MockChooserController : public ChooserController {
- public:
-  enum ConnectedPairedStatus {
-    NONE = 0,
-    CONNECTED = 1 << 0,
-    PAIRED = 1 << 1,
-  };
-
-  MockChooserController();
-  ~MockChooserController() override;
-
-  // ChooserController:
-  bool ShouldShowIconBeforeText() const override;
-  base::string16 GetNoOptionsText() const override;
-  base::string16 GetOkButtonLabel() const override;
-  size_t NumOptions() const override;
-  int GetSignalStrengthLevel(size_t index) const override;
-  base::string16 GetOption(size_t index) const override;
-  bool IsConnected(size_t index) const override;
-  bool IsPaired(size_t index) const override;
-  base::string16 GetStatus() const override;
-  MOCK_METHOD0(RefreshOptions, void());
-  MOCK_METHOD1(Select, void(const std::vector<size_t>& indices));
-  MOCK_METHOD0(Cancel, void());
-  MOCK_METHOD0(Close, void());
-  MOCK_CONST_METHOD0(OpenHelpCenterUrl, void());
-  MOCK_CONST_METHOD0(OpenAdapterOffHelpUrl, void());
-
-  void OnAdapterPresenceChanged(
-      content::BluetoothChooser::AdapterPresence presence);
-  void OnDiscoveryStateChanged(content::BluetoothChooser::DiscoveryState state);
-
-  void OptionAdded(const base::string16& option_name,
-                   int signal_strength_level,
-                   int connected_paired_status);
-  void OptionRemoved(const base::string16& option_name);
-  void OptionUpdated(const base::string16& previous_option_name,
-                     const base::string16& new_option_name,
-                     int new_signal_strengh_level,
-                     int new_connected_paired_status);
-
-  static const int kNoSignalStrengthLevelImage;
-  static const int kSignalStrengthLevel0Bar;
-  static const int kSignalStrengthLevel1Bar;
-  static const int kSignalStrengthLevel2Bar;
-  static const int kSignalStrengthLevel3Bar;
-  static const int kSignalStrengthLevel4Bar;
-  static const int kImageColorUnselected;
-  static const int kImageColorSelected;
-
- private:
-  void ClearAllOptions();
-
-  struct OptionInfo {
-    base::string16 name;
-    int signal_strength_level;
-    // This value is the '|' of ConnectedPairedStatus values.
-    int connected_paired_status;
-  };
-
-  std::vector<OptionInfo> options_;
-  base::string16 status_text_;
-
-  DISALLOW_COPY_AND_ASSIGN(MockChooserController);
-};
-
-#endif  // CHROME_BROWSER_CHOOSER_CONTROLLER_MOCK_CHOOSER_CONTROLLER_H_
diff --git a/chrome/browser/chrome_browser_main_win.cc b/chrome/browser/chrome_browser_main_win.cc
index 978deb0..9a75cff 100644
--- a/chrome/browser/chrome_browser_main_win.cc
+++ b/chrome/browser/chrome_browser_main_win.cc
@@ -63,7 +63,6 @@
 #include "chrome/grit/chromium_strings.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/install_static/install_details.h"
-#include "chrome/installer/util/browser_distribution.h"
 #include "chrome/installer/util/helper.h"
 #include "chrome/installer/util/install_util.h"
 #include "chrome/installer/util/installer_util_strings.h"
@@ -438,10 +437,9 @@
           ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
           ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR,
       };
-      BrowserDistribution* dist = BrowserDistribution::GetDistribution();
       for (size_t i = 0; i < arraysize(user_shortcut_locations); ++i) {
-        if (!ShellUtil::RemoveShortcuts(user_shortcut_locations[i], dist,
-                ShellUtil::CURRENT_USER, chrome_exe)) {
+        if (!ShellUtil::RemoveShortcuts(user_shortcut_locations[i],
+                                        ShellUtil::CURRENT_USER, chrome_exe)) {
           VLOG(1) << "Failed to delete shortcut at location "
                   << user_shortcut_locations[i];
         }
diff --git a/chrome/browser/chrome_service_worker_browsertest.cc b/chrome/browser/chrome_service_worker_browsertest.cc
index a2091a3..d42a460d 100644
--- a/chrome/browser/chrome_service_worker_browsertest.cc
+++ b/chrome/browser/chrome_service_worker_browsertest.cc
@@ -34,7 +34,7 @@
 #include "content/public/test/browser_test_utils.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "ppapi/shared_impl/ppapi_switches.h"
-#include "third_party/blink/public/common/message_port/string_message_codec.h"
+#include "third_party/blink/public/common/messaging/string_message_codec.h"
 
 namespace {
 
diff --git a/chrome/browser/chromeos/android_sms/connection_establisher_impl.cc b/chrome/browser/chromeos/android_sms/connection_establisher_impl.cc
index 4d8c91a..124cd453 100644
--- a/chrome/browser/chromeos/android_sms/connection_establisher_impl.cc
+++ b/chrome/browser/chromeos/android_sms/connection_establisher_impl.cc
@@ -8,7 +8,7 @@
 #include "chrome/browser/chromeos/android_sms/android_sms_urls.h"
 #include "chromeos/components/proximity_auth/logging/logging.h"
 #include "content/public/browser/browser_thread.h"
-#include "third_party/blink/public/common/message_port/string_message_codec.h"
+#include "third_party/blink/public/common/messaging/string_message_codec.h"
 
 namespace chromeos {
 
diff --git a/chrome/browser/chromeos/android_sms/connection_establisher_impl_unittest.cc b/chrome/browser/chromeos/android_sms/connection_establisher_impl_unittest.cc
index e6041a2..cc9bd509 100644
--- a/chrome/browser/chromeos/android_sms/connection_establisher_impl_unittest.cc
+++ b/chrome/browser/chromeos/android_sms/connection_establisher_impl_unittest.cc
@@ -10,7 +10,7 @@
 #include "content/public/test/fake_service_worker_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/message_port/string_message_codec.h"
+#include "third_party/blink/public/common/messaging/string_message_codec.h"
 
 namespace chromeos {
 
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_data_base.cc b/chrome/browser/chromeos/app_mode/kiosk_app_data_base.cc
index 61b984e..0ad5b57 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_data_base.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_data_base.cc
@@ -9,7 +9,7 @@
 #include "base/files/file_util.h"
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
-#include "base/threading/thread_restrictions.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "chrome/browser/browser_process.h"
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
@@ -32,7 +32,7 @@
 // Save |raw_icon| for given |app_id|.
 void SaveIconToLocalOnBlockingPool(const base::FilePath& icon_path,
                                    std::vector<unsigned char> image_data) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   const base::FilePath dir = icon_path.DirName();
   if (!base::PathExists(dir) && !base::CreateDirectory(dir)) {
     LOG(ERROR) << "Failed to create directory to store kiosk icons";
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util.cc b/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util.cc
index 3c5d225..c85555b 100644
--- a/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util.cc
+++ b/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util.cc
@@ -217,6 +217,30 @@
   return std::vector<base::FilePath::StringType>();
 }
 
+std::string StripMimeSubType(const std::string& mime_type) {
+  if (mime_type.empty())
+    return mime_type;
+  size_t index = mime_type.find_first_of('/', 0);
+  if (index == 0 || index == mime_type.size() - 1 ||
+      index == std::string::npos) {
+    // This looks malformed, return an empty string.
+    return std::string();
+  }
+  return mime_type.substr(0, index);
+}
+
+// This is based on net/base/mime_util.cc: net::FindMimeType.
+std::string FindArcMimeTypeFromExtension(const std::string& ext) {
+  for (const auto& mapping : kAndroidMimeTypeMappings) {
+    std::vector<base::StringPiece> extensions = base::SplitStringPiece(
+        mapping.extensions, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+    auto iter = std::find(extensions.begin(), extensions.end(), ext);
+    if (iter != extensions.end())
+      return mapping.mime_type;
+  }
+  return std::string();
+}
+
 // TODO(crbug.com/675868): Consolidate with the similar logic for Drive.
 base::FilePath::StringType GetFileNameForDocument(
     const mojom::DocumentPtr& document) {
@@ -243,10 +267,23 @@
     extension = extension.substr(1);  // Strip the leading dot.
   std::vector<base::FilePath::StringType> possible_extensions =
       GetExtensionsForArcMimeType(document->mime_type);
+
   if (!possible_extensions.empty() &&
       !base::ContainsValue(possible_extensions, extension)) {
-    filename =
-        base::FilePath(filename).AddExtension(possible_extensions[0]).value();
+    // Lookup the extension in the hardcoded map before appending an extension,
+    // as some extensions (eg. 3gp) are typed differently by Android. Only
+    // append the suggested extension if the lookup fails (i.e. no valid mime
+    // type returned), or the returned mime type is of a different category.
+    // TODO(crbug.com/878221): Fix discrepancy in MIME types and extensions
+    // between the hard coded map and the Android content provider.
+    std::string missed_possible_mime_type =
+        FindArcMimeTypeFromExtension(extension);
+    if (missed_possible_mime_type.empty() ||
+        StripMimeSubType(document->mime_type) !=
+            StripMimeSubType(missed_possible_mime_type)) {
+      filename =
+          base::FilePath(filename).AddExtension(possible_extensions[0]).value();
+    }
   }
 
   return filename;
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util.h b/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util.h
index 8313472..af15679 100644
--- a/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util.h
+++ b/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util.h
@@ -75,6 +75,14 @@
 base::FilePath::StringType GetFileNameForDocument(
     const mojom::DocumentPtr& document);
 
+// Returns the provided MIME type without the subtype component.
+std::string StripMimeSubType(const std::string& mime_type);
+
+// Finds the first matching mime type with |ext| as a valid extension from the
+// internal list of Android mime types. On success, the first matching MIME type
+// is returned. On failure, nullptr is returned.
+std::string FindArcMimeTypeFromExtension(const std::string& ext);
+
 }  // namespace arc
 
 #endif  // CHROME_BROWSER_CHROMEOS_ARC_FILEAPI_ARC_DOCUMENTS_PROVIDER_UTIL_H_
diff --git a/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util_unittest.cc b/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util_unittest.cc
index 424b057..33dd1752 100644
--- a/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util_unittest.cc
+++ b/chrome/browser/chromeos/arc/fileapi/arc_documents_provider_util_unittest.cc
@@ -243,6 +243,49 @@
             GetFileNameForDocument(MakeDocument("kitten", "image/png")));
   EXPECT_EQ("kitten",
             GetFileNameForDocument(MakeDocument("kitten", "abc/xyz")));
+
+  // Check that files with a mime type different than expected appends a
+  // possible extension when a different mime type with a different category is
+  // found in the Android mime types map.
+  EXPECT_EQ("file.txt.3gp",
+            GetFileNameForDocument(MakeDocument("file.txt", "video/3gpp")));
+
+  // Check that files with a mime type different than expected don't append
+  // an extension when a different mime type with the same category is
+  // found in the Android mime types map.
+  EXPECT_EQ("file.3gp",
+            GetFileNameForDocument(MakeDocument("file.3gp", "video/mp4")));
+}
+
+TEST(ArcDocumentsProviderUtilTest, StripMimeSubType) {
+  // Check that the category type is returned for a valid mime type.
+  EXPECT_EQ("video", StripMimeSubType("video/mp4"));
+  // Check that an empty string is returned for malformed mime types.
+  EXPECT_EQ("", StripMimeSubType(""));
+  EXPECT_EQ("", StripMimeSubType("video/"));
+  EXPECT_EQ("", StripMimeSubType("/"));
+  EXPECT_EQ("", StripMimeSubType("/abc"));
+  EXPECT_EQ("", StripMimeSubType("/abc/xyz"));
+}
+
+TEST(ArcDocumentsProviderUtilTest, FindArcMimeTypeFromExtension) {
+  // Test that a lone possible extension returns the correct type.
+  EXPECT_EQ("application/msword", FindArcMimeTypeFromExtension("doc"));
+  // Test that the first extension in the comma delimited list of extensions
+  // returns the correct type.
+  EXPECT_EQ("video/3gpp", FindArcMimeTypeFromExtension("3gp"));
+  // Test that the second extension in the comma delimited list of extensions
+  // returns the correct type.
+  EXPECT_EQ("audio/mpeg", FindArcMimeTypeFromExtension("mpga"));
+  // Test that matching suffixes (m4a) return null without a full match.
+  EXPECT_EQ("", FindArcMimeTypeFromExtension("4a"));
+  // Test that matching prefixes (imy) return null without a full match.
+  EXPECT_EQ("", FindArcMimeTypeFromExtension("im"));
+  // Test that ambiguous prefixes (mp4, mpg) return null.
+  EXPECT_EQ("", FindArcMimeTypeFromExtension("mp"));
+  // Test that invalid mime types return null.
+  EXPECT_EQ("", FindArcMimeTypeFromExtension(""));
+  EXPECT_EQ("", FindArcMimeTypeFromExtension("invalid"));
 }
 
 }  // namespace
diff --git a/chrome/browser/chromeos/customization/customization_document.cc b/chrome/browser/chromeos/customization/customization_document.cc
index 74e1e5d3..2385bdd7 100644
--- a/chrome/browser/chromeos/customization/customization_document.cc
+++ b/chrome/browser/chromeos/customization/customization_document.cc
@@ -24,7 +24,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
-#include "base/threading/thread_restrictions.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "base/time/time.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/customization/customization_wallpaper_downloader.h"
@@ -157,7 +157,7 @@
 }
 
 std::string ReadFileInBackground(const base::FilePath& file) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
 
   std::string manifest;
   if (!base::ReadFileToString(file, &manifest)) {
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.cc b/chrome/browser/chromeos/drive/drive_integration_service.cc
index eac49a38..36591925 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.cc
+++ b/chrome/browser/chromeos/drive/drive_integration_service.cc
@@ -325,6 +325,16 @@
   // net::NetworkChangeNotifier::NetworkChangeObserver
   void OnNetworkChanged(
       net::NetworkChangeNotifier::ConnectionType type) override {
+    // Check for a pending remount first. In this case, DriveFS will not be
+    // mounted and thus its interface will be null.
+    if (integration_service_->drivefs_holder_ &&
+        integration_service_->remount_when_online_ &&
+        !net::NetworkChangeNotifier::IsOffline()) {
+      integration_service_->remount_when_online_ = false;
+      integration_service_->AddDriveMountPoint();
+      return;
+    }
+
     if (!integration_service_->GetDriveFsInterface())
       return;
 
@@ -345,12 +355,13 @@
 class DriveIntegrationService::DriveFsHolder
     : public drivefs::DriveFsHost::Delegate {
  public:
-  DriveFsHolder(Profile* profile,
-                base::RepeatingClosure on_drivefs_mounted,
-                base::RepeatingCallback<void(base::Optional<base::TimeDelta>)>
-                    on_drivefs_unmounted,
-                DriveFsMojoConnectionDelegateFactory
-                    test_drivefs_mojo_connection_delegate_factory)
+  DriveFsHolder(
+      Profile* profile,
+      base::RepeatingClosure on_drivefs_mounted,
+      base::RepeatingCallback<void(base::Optional<base::TimeDelta>,
+                                   bool failed_to_mount)> on_drivefs_unmounted,
+      DriveFsMojoConnectionDelegateFactory
+          test_drivefs_mojo_connection_delegate_factory)
       : profile_(profile),
         on_drivefs_mounted_(std::move(on_drivefs_mounted)),
         on_drivefs_unmounted_(std::move(on_drivefs_unmounted)),
@@ -385,7 +396,7 @@
   }
 
   void OnMountFailed(base::Optional<base::TimeDelta> remount_delay) override {
-    on_drivefs_unmounted_.Run(std::move(remount_delay));
+    on_drivefs_unmounted_.Run(std::move(remount_delay), true);
   }
 
   void OnMounted(const base::FilePath& path) override {
@@ -393,7 +404,7 @@
   }
 
   void OnUnmounted(base::Optional<base::TimeDelta> remount_delay) override {
-    on_drivefs_unmounted_.Run(std::move(remount_delay));
+    on_drivefs_unmounted_.Run(std::move(remount_delay), false);
   }
 
   const std::string& GetProfileSalt() {
@@ -420,7 +431,8 @@
 
   // Invoked when DriveFS mounting is completed.
   const base::RepeatingClosure on_drivefs_mounted_;
-  const base::RepeatingCallback<void(base::Optional<base::TimeDelta>)>
+  const base::RepeatingCallback<void(base::Optional<base::TimeDelta>,
+                                     bool failed_to_mount)>
       on_drivefs_unmounted_;
 
   const DriveFsMojoConnectionDelegateFactory
@@ -820,6 +832,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   weak_ptr_factory_.InvalidateWeakPtrs();
+  remount_when_online_ = false;
 
   if (!mount_point_name_.empty()) {
     if (!drivefs_holder_)
@@ -838,12 +851,19 @@
 }
 
 void DriveIntegrationService::MaybeRemountFileSystem(
-    base::Optional<base::TimeDelta> remount_delay) {
+    base::Optional<base::TimeDelta> remount_delay,
+    bool failed_to_mount) {
   DCHECK_EQ(INITIALIZED, state_);
 
   RemoveDriveMountPoint();
 
   if (!remount_delay) {
+    if (failed_to_mount && net::NetworkChangeNotifier::IsOffline()) {
+      logger_->Log(logging::LOG_WARNING,
+                   "DriveFs failed to start, will retry when online.");
+      remount_when_online_ = true;
+      return;
+    }
     // If DriveFs didn't specify retry time it's likely unexpected error, e.g.
     // crash. Use limited exponential backoff for retry.
     ++drivefs_consecutive_failures_count_;
diff --git a/chrome/browser/chromeos/drive/drive_integration_service.h b/chrome/browser/chromeos/drive/drive_integration_service.h
index b33de95..5313d0d6e 100644
--- a/chrome/browser/chromeos/drive/drive_integration_service.h
+++ b/chrome/browser/chromeos/drive/drive_integration_service.h
@@ -193,8 +193,11 @@
                               FileError error);
 
   // Unregisters drive mount point, and if |remount_delay| is specified
-  // then tries to add it back after that delay.
-  void MaybeRemountFileSystem(base::Optional<base::TimeDelta> remount_delay);
+  // then tries to add it back after that delay. If |remount_delay| isn't
+  // specified, |failed_to_mount| is true and the user is offline, schedules a
+  // retry when the user is online.
+  void MaybeRemountFileSystem(base::Optional<base::TimeDelta> remount_delay,
+                              bool failed_to_mount);
 
   // Initializes the object. This function should be called before any
   // other functions.
@@ -251,6 +254,7 @@
   std::unique_ptr<NotificationManager> notification_manager_;
   int drivefs_total_failures_count_ = 0;
   int drivefs_consecutive_failures_count_ = 0;
+  bool remount_when_online_ = false;
 
   // Note: This should remain the last member so it'll be destroyed and
   // invalidate its weak pointers before any other members are destroyed.
diff --git a/chrome/browser/chromeos/extensions/active_tab_permission_granter_delegate_chromeos.cc b/chrome/browser/chromeos/extensions/active_tab_permission_granter_delegate_chromeos.cc
index e70f05e..765f46f 100644
--- a/chrome/browser/chromeos/extensions/active_tab_permission_granter_delegate_chromeos.cc
+++ b/chrome/browser/chromeos/extensions/active_tab_permission_granter_delegate_chromeos.cc
@@ -36,6 +36,12 @@
   if (g_resolved_callback)
     callback = *g_resolved_callback;
 
+  if (!profiles::ArePublicSessionRestrictionsEnabled()) {
+    if (callback)
+      callback.Run({APIPermission::kActiveTab});
+    return true;
+  }
+
   bool already_handled = permission_helper::HandlePermissionRequest(
       *extension, {APIPermission::kActiveTab}, web_contents, callback,
       permission_helper::PromptFactory());
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
index 9497f1a..5e7d136e 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest.cc
@@ -15,6 +15,7 @@
 #include "components/session_manager/core/session_manager.h"
 #include "components/user_manager/user_manager.h"
 #include "services/identity/public/cpp/identity_manager.h"
+#include "ui/keyboard/keyboard_switches.h"
 
 namespace file_manager {
 
@@ -120,9 +121,11 @@
                                       "TrustedEventsDefaultAction");
     }
 
-    // Default mode is clamshell: force Ash into tablet mode if requested.
+    // Default mode is clamshell: force Ash into tablet mode if requested,
+    // and enable the Ash virtual keyboard sub-system therein.
     if (GetParam().tablet_mode) {
       command_line->AppendSwitchASCII("force-tablet-mode", "touch_view");
+      command_line->AppendSwitch(keyboard::switches::kEnableVirtualKeyboard);
     }
 
     // TODO(crbug.com/879404): Fix tests to work with NativeSMB.
@@ -144,15 +147,15 @@
     return "file_manager_test_manifest.json";
   }
 
+  bool GetTabletMode() const override { return GetParam().tablet_mode; }
+
   bool GetEnableDriveFs() const override { return GetParam().enable_drivefs; }
 
   bool GetRequiresStartupBrowser() const override {
     return GetParam().with_browser;
   }
 
-  bool GetNeedsZipSupport() const override {
-    return GetParam().needs_zip;
-  }
+  bool GetNeedsZipSupport() const override { return GetParam().needs_zip; }
 
   bool GetIsOffline() const override { return GetParam().offline; }
 
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
index b0a86f9b1..00382c2 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.cc
@@ -1051,6 +1051,10 @@
   test::AddDefaultComponentExtensionsOnMainThread(profile());
 }
 
+bool FileManagerBrowserTestBase::GetTabletMode() const {
+  return false;
+}
+
 bool FileManagerBrowserTestBase::GetEnableDriveFs() const {
   return false;
 }
diff --git a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h
index b428d248..af45f7a0 100644
--- a/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h
+++ b/chrome/browser/chromeos/file_manager/file_manager_browsertest_base.h
@@ -38,11 +38,14 @@
   void SetUpInProcessBrowserTestFixture() override;
   void SetUpOnMainThread() override;
 
-  // Overrides for each FileManagerBrowserTest test extension type.
+  // Mandatory overrides for each File Manager test extension type.
   virtual GuestMode GetGuestMode() const = 0;
   virtual const char* GetTestCaseName() const = 0;
   virtual std::string GetFullTestCaseName() const = 0;
   virtual const char* GetTestExtensionManifestName() const = 0;
+
+  // Optional overrides for each File Manager test extension type.
+  virtual bool GetTabletMode() const;
   virtual bool GetEnableDriveFs() const;
   virtual bool GetRequiresStartupBrowser() const;
   virtual bool GetNeedsZipSupport() const;
@@ -60,6 +63,9 @@
   // Returns true if the test requires in guest mode.
   bool IsGuestModeTest() const { return GetGuestMode() == IN_GUEST_MODE; }
 
+  // Returns true if the test runs in tablet mode (aka Ash immersive mode).
+  bool IsTabletModeTest() const { return GetTabletMode(); }
+
   // Returns true if the test requires DriveFS.
   bool IsDriveFsTest() const { return GetEnableDriveFs(); }
 
diff --git a/chrome/browser/chromeos/file_manager/url_util.cc b/chrome/browser/chromeos/file_manager/url_util.cc
index 0c217fd4..21c4ae4f 100644
--- a/chrome/browser/chromeos/file_manager/url_util.cc
+++ b/chrome/browser/chromeos/file_manager/url_util.cc
@@ -11,6 +11,7 @@
 #include "base/json/json_writer.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/file_manager/app_id.h"
+#include "chromeos/chromeos_features.h"
 #include "net/base/escape.h"
 
 namespace file_manager {
@@ -116,7 +117,10 @@
   if (file_types) {
     switch (file_types->allowed_paths) {
       case ui::SelectFileDialog::FileTypeInfo::NATIVE_PATH:
-        arg_value.SetString(kAllowedPaths, kNativePath);
+        if (base::FeatureList::IsEnabled(chromeos::features::kDriveFs))
+          arg_value.SetString(kAllowedPaths, kNativeOrDrivePath);
+        else
+          arg_value.SetString(kAllowedPaths, kNativePath);
         break;
       case ui::SelectFileDialog::FileTypeInfo::NATIVE_OR_DRIVE_PATH:
         arg_value.SetString(kAllowedPaths, kNativeOrDrivePath);
@@ -125,6 +129,8 @@
         arg_value.SetString(kAllowedPaths, kAnyPath);
         break;
     }
+  } else if (base::FeatureList::IsEnabled(chromeos::features::kDriveFs)) {
+    arg_value.SetString(kAllowedPaths, kNativeOrDrivePath);
   } else {
     arg_value.SetString(kAllowedPaths, kNativePath);
   }
diff --git a/chrome/browser/chromeos/login/configuration_keys.cc b/chrome/browser/chromeos/login/configuration_keys.cc
index c20e6d8e6..61da12d 100644
--- a/chrome/browser/chromeos/login/configuration_keys.cc
+++ b/chrome/browser/chromeos/login/configuration_keys.cc
@@ -44,6 +44,27 @@
 // enrollment at appropriate moment.
 const char kWizardAutoEnroll[] = "wizardAutoEnroll";
 
+// String value, containing device requisition parameter.
+const char kDeviceRequisition[] = "deviceRequisition";
+
+// == Enrollment screen
+
+// String value indicating which license type should automatically be used if
+// license selection is done on a client side.
+const char kEnrollmentLicenseType[] = "enrollmentLicenseType";
+
+// String value indicating what value would be propagated to Asset ID field
+// on Device Attributes step.
+const char kEnrollmentAssetId[] = "enrollmentAssetId";
+
+// String value indicating what value would be propagated to Location field
+// on Device Attributes step.
+const char kEnrollmentLocation[] = "enrollmentLocation";
+
+// Boolean value, controls if device attributes step should proceed with preset
+// values.
+const char kEnrollmentAutoAttributes[] = "enrollmentAutoAttributes";
+
 using ValueType = base::Value::Type;
 
 constexpr struct {
@@ -61,6 +82,14 @@
      ConfigurationHandlerSide::HANDLER_CPP},
     {kWizardAutoEnroll, ValueType::BOOLEAN,
      ConfigurationHandlerSide::HANDLER_CPP},
+    {kDeviceRequisition, ValueType::STRING,
+     ConfigurationHandlerSide::HANDLER_CPP},
+    {kEnrollmentLicenseType, ValueType::STRING,
+     ConfigurationHandlerSide::HANDLER_CPP},
+    {kEnrollmentLocation, ValueType::STRING,
+     ConfigurationHandlerSide::HANDLER_CPP},
+    {kEnrollmentLocation, ValueType::BOOLEAN,
+     ConfigurationHandlerSide::HANDLER_CPP},
     {"desc", ValueType::STRING, ConfigurationHandlerSide::HANDLER_DOC},
     {"testValue", ValueType::STRING, ConfigurationHandlerSide::HANDLER_BOTH},
 };
diff --git a/chrome/browser/chromeos/login/configuration_keys.h b/chrome/browser/chromeos/login/configuration_keys.h
index 7694975..2374186 100644
--- a/chrome/browser/chromeos/login/configuration_keys.h
+++ b/chrome/browser/chromeos/login/configuration_keys.h
@@ -16,14 +16,20 @@
 
 extern const char kNetworkSelectGUID[];
 
-extern const char kEULASendUsageStatistics[];
+extern const char kDeviceRequisition[];
 
+extern const char kEULASendUsageStatistics[];
 extern const char kEULAAutoAccept[];
 
 extern const char kUpdateSkipUpdate[];
 
 extern const char kWizardAutoEnroll[];
 
+extern const char kEnrollmentLicenseType[];
+extern const char kEnrollmentAssetId[];
+extern const char kEnrollmentLocation[];
+extern const char kEnrollmentAutoAttributes[];
+
 enum class ConfigurationHandlerSide : unsigned int {
   HANDLER_JS,    // Handled by JS code
   HANDLER_CPP,   // Handled by C++ code
@@ -40,7 +46,6 @@
 void FilterConfiguration(const base::Value& configuration,
                          ConfigurationHandlerSide side,
                          base::Value& filtered_result);
-
 }  // namespace configuration
 }  // namespace chromeos
 
diff --git a/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc b/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc
index 8a1cae8..28c2fe72 100644
--- a/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc
+++ b/chrome/browser/chromeos/login/enrollment/enrollment_screen.cc
@@ -12,6 +12,7 @@
 #include "base/timer/elapsed_timer.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part.h"
+#include "chrome/browser/chromeos/login/configuration_keys.h"
 #include "chrome/browser/chromeos/login/enrollment/enrollment_uma.h"
 #include "chrome/browser/chromeos/login/screen_manager.h"
 #include "chrome/browser/chromeos/login/screens/base_screen_delegate.h"
@@ -313,6 +314,22 @@
 
 void EnrollmentScreen::OnMultipleLicensesAvailable(
     const EnrollmentLicenseMap& licenses) {
+  if (GetConfiguration()) {
+    auto* license_type_value = GetConfiguration()->FindKeyOfType(
+        configuration::kEnrollmentLicenseType, base::Value::Type::STRING);
+    if (license_type_value) {
+      const std::string& license_type = license_type_value->GetString();
+      for (const auto& it : licenses) {
+        if (license_type == GetLicenseIdByType(it.first) && it.second > 0) {
+          VLOG(1) << "Using License type from configuration " << license_type;
+          OnLicenseTypeSelected(license_type);
+          return;
+        }
+      }
+      VLOG(1) << "No licenses for License type from configuration "
+              << license_type;
+    }
+  }
   base::DictionaryValue license_dict;
   for (const auto& it : licenses)
     license_dict.SetInteger(GetLicenseIdByType(it.first), it.second);
@@ -402,12 +419,45 @@
   policy::DeviceCloudPolicyManagerChromeOS* policy_manager =
       connector->GetDeviceCloudPolicyManager();
 
+  std::string asset_id;
+  std::string location;
+
+  if (GetConfiguration()) {
+    auto* asset_id_value = GetConfiguration()->FindKeyOfType(
+        configuration::kEnrollmentAssetId, base::Value::Type::STRING);
+    if (asset_id_value) {
+      VLOG(1) << "Using Asset ID from configuration "
+              << asset_id_value->GetString();
+      asset_id = asset_id_value->GetString();
+    }
+    auto* location_value = GetConfiguration()->FindKeyOfType(
+        configuration::kEnrollmentLocation, base::Value::Type::STRING);
+    if (location_value) {
+      VLOG(1) << "Using Location from configuration "
+              << location_value->GetString();
+      location = location_value->GetString();
+    }
+  }
+
   policy::CloudPolicyStore* store = policy_manager->core()->store();
 
   const enterprise_management::PolicyData* policy = store->policy();
 
-  std::string asset_id = policy ? policy->annotated_asset_id() : std::string();
-  std::string location = policy ? policy->annotated_location() : std::string();
+  if (policy) {
+    asset_id = policy->annotated_asset_id();
+    location = policy->annotated_location();
+  }
+
+  if (GetConfiguration()) {
+    auto* auto_attributes = GetConfiguration()->FindKeyOfType(
+        configuration::kEnrollmentAutoAttributes, base::Value::Type::BOOLEAN);
+    if (auto_attributes && auto_attributes->GetBool()) {
+      VLOG(1) << "Automatically accept attributes";
+      OnDeviceAttributeProvided(asset_id, location);
+      return;
+    }
+  }
+
   view_->ShowAttributePromptScreen(asset_id, location);
 }
 
diff --git a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
index 9dcc85c8..621c727 100644
--- a/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
+++ b/chrome/browser/chromeos/login/enterprise_enrollment_browsertest.cc
@@ -4,6 +4,7 @@
 
 #include "base/macros.h"
 #include "build/build_config.h"
+#include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/enrollment/enrollment_screen.h"
 #include "chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper.h"
 #include "chrome/browser/chromeos/login/enrollment/enterprise_enrollment_helper_impl.h"
@@ -15,6 +16,7 @@
 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
 #include "chrome/browser/chromeos/login/ui/login_display_host.h"
 #include "chrome/browser/chromeos/login/wizard_controller.h"
+#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
 #include "chrome/browser/chromeos/policy/enrollment_status_chromeos.h"
 #include "chromeos/chromeos_test_utils.h"
 #include "chromeos/dbus/dbus_switches.h"
@@ -744,4 +746,19 @@
   // We have to remove the enrollment_helper before the dtor gets called.
   ResetHelper();
 }
+
+// Check that when configuration has requisition, it gets applied at the
+// beginning.
+IN_PROC_BROWSER_TEST_F(EnterpriseEnrollmentConfigurationTest,
+                       TestDeviceRequisition) {
+  StartWizard();
+  LoadConfiguration();
+  OobeScreenWaiter(OobeScreen::SCREEN_OOBE_EULA).Wait();
+  auto* policy_manager = g_browser_process->platform_part()
+                             ->browser_policy_connector_chromeos()
+                             ->GetDeviceCloudPolicyManager();
+  EXPECT_EQ(policy_manager->GetDeviceRequisition(), "some_requisition");
+  // We have to remove the enrollment_helper before the dtor gets called.
+  ResetHelper();
+}
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
index 296ce14..aa42f5c 100644
--- a/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
+++ b/chrome/browser/chromeos/login/ui/login_display_host_webui.cc
@@ -939,9 +939,10 @@
   if (login_window_)
     return;
 
-  if (system::InputDeviceSettings::Get()->ForceKeyboardDrivenUINavigation()) {
+  // TODO(crbug.com/881390): Mash support for keyboard driven OOBE.
+  if (!features::IsMultiProcessMash() &&
+      system::InputDeviceSettings::ForceKeyboardDrivenUINavigation()) {
     views::FocusManager::set_arrow_key_traversal_enabled(true);
-    // crbug.com/405859
     focus_ring_controller_ = std::make_unique<ash::FocusRingController>();
     focus_ring_controller_->SetVisible(true);
 
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
index c5111bb..556866c 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.cc
@@ -230,6 +230,13 @@
   return std::unique_ptr<ChromeUserManager>(new ChromeUserManagerImpl());
 }
 
+// static
+void ChromeUserManagerImpl::ResetPublicAccountDelegatesForTesting() {
+  delete extensions::PermissionsUpdater::SetPlatformDelegate(nullptr);
+  delete extensions::ExtensionTabUtil::SetPlatformDelegate(nullptr);
+  delete extensions::ActiveTabPermissionGranter::SetPlatformDelegate(nullptr);
+}
+
 ChromeUserManagerImpl::ChromeUserManagerImpl()
     : ChromeUserManager(base::ThreadTaskRunnerHandle::IsSet()
                             ? base::ThreadTaskRunnerHandle::Get()
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
index ec1e09e5..99929993 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_impl.h
@@ -69,6 +69,9 @@
   // Registers user manager preferences.
   static void RegisterPrefs(PrefRegistrySimple* registry);
 
+  // Resets platform specific delegates that were set for public accounts.
+  static void ResetPublicAccountDelegatesForTesting();
+
   // UserManagerInterface implementation:
   MultiProfileUserController* GetMultiProfileUserController() override;
   UserImageManager* GetUserImageManager(const AccountId& account_id) override;
diff --git a/chrome/browser/chromeos/login/users/chrome_user_manager_util.cc b/chrome/browser/chromeos/login/users/chrome_user_manager_util.cc
index 03a3ac8..60060cae 100644
--- a/chrome/browser/chromeos/login/users/chrome_user_manager_util.cc
+++ b/chrome/browser/chromeos/login/users/chrome_user_manager_util.cc
@@ -51,13 +51,17 @@
 }
 
 bool IsManagedSessionEnabled(const user_manager::User* active_user) {
+  // If the service doesn't exist or the policy is not set, enable managed
+  // session by default.
+  const bool managed_session_enabled_by_default = true;
+
   policy::DeviceLocalAccountPolicyService* service =
       g_browser_process->platform_part()
           ->browser_policy_connector_chromeos()
           ->GetDeviceLocalAccountPolicyService();
 
   if (!service)
-    return false;
+    return managed_session_enabled_by_default;
 
   const policy::PolicyMap::Entry* entry =
       service->GetBrokerForUser(active_user->GetAccountId().GetUserEmail())
@@ -66,9 +70,8 @@
           ->policy_map()
           .Get(policy::key::kDeviceLocalAccountManagedSessionEnabled);
 
-  // If the policy is not set, enable managed session by default.
   if (!entry)
-    return true;
+    return managed_session_enabled_by_default;
 
   return entry && entry->value && entry->value->GetBool();
 }
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc
index 269c0ea..6f24bc90 100644
--- a/chrome/browser/chromeos/login/wizard_controller.cc
+++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -320,8 +320,8 @@
         base::Bind(&WizardController::OnAccessibilityStatusChanged,
                    weak_factory_.GetWeakPtr()));
   }
-  oobe_configuration_ = OobeConfiguration::Get()->GetConfiguration().Clone();
   OobeConfiguration::Get()->AddObserver(this);
+  OnOobeConfigurationChanged();
 }
 
 WizardController::~WizardController() {
@@ -1431,6 +1431,18 @@
   if (current_screen_) {
     current_screen_->SetConfiguration(&oobe_configuration_, true /*notify */);
   }
+  auto* requisition_value = oobe_configuration_.FindKeyOfType(
+      configuration::kDeviceRequisition, base::Value::Type::STRING);
+  if (requisition_value) {
+    auto* policy_manager = g_browser_process->platform_part()
+                               ->browser_policy_connector_chromeos()
+                               ->GetDeviceCloudPolicyManager();
+    if (policy_manager) {
+      VLOG(1) << "Using Device Requisition from configuration"
+              << requisition_value->GetString();
+      policy_manager->SetDeviceRequisition(requisition_value->GetString());
+    }
+  }
 }
 
 void WizardController::AdvanceToScreen(OobeScreen screen) {
diff --git a/chrome/browser/chromeos/mobile/mobile_activator.cc b/chrome/browser/chromeos/mobile/mobile_activator.cc
index 8054efbc..ab63db8 100644
--- a/chrome/browser/chromeos/mobile/mobile_activator.cc
+++ b/chrome/browser/chromeos/mobile/mobile_activator.cc
@@ -21,7 +21,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task/post_task.h"
-#include "base/threading/thread_restrictions.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "base/timer/timer.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
@@ -102,7 +102,7 @@
 }
 
 void CellularConfigDocument::LoadCellularConfigFile() {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
 
   // Load partner customization startup manifest if it is available.
   base::FilePath config_path(kCellularConfigPath);
diff --git a/chrome/browser/chromeos/mobile_config.cc b/chrome/browser/chromeos/mobile_config.cc
index 02b865da..6c3eb22 100644
--- a/chrome/browser/chromeos/mobile_config.cc
+++ b/chrome/browser/chromeos/mobile_config.cc
@@ -15,7 +15,7 @@
 #include "base/logging.h"
 #include "base/stl_util.h"
 #include "base/task/post_task.h"
-#include "base/threading/thread_restrictions.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/startup_utils.h"
@@ -62,7 +62,7 @@
 chromeos::MobileConfig::Config ReadConfigInBackground(
     const base::FilePath& global_config_file,
     const base::FilePath& local_config_file) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
 
   chromeos::MobileConfig::Config config;
   if (!base::ReadFileToString(global_config_file, &config.global_config)) {
diff --git a/chrome/browser/chromeos/power/process_data_collector.cc b/chrome/browser/chromeos/power/process_data_collector.cc
index e6b4a8b..08b04fe 100644
--- a/chrome/browser/chromeos/power/process_data_collector.cc
+++ b/chrome/browser/chromeos/power/process_data_collector.cc
@@ -31,7 +31,7 @@
 #include "base/synchronization/lock.h"
 #include "base/task/post_task.h"
 #include "base/threading/platform_thread.h"
-#include "base/threading/thread_restrictions.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "base/time/time.h"
 #include "base/values.h"
 #include "chrome/browser/chromeos/system/procfs_util.h"
@@ -79,7 +79,7 @@
 base::Optional<pid_t> GetAndroidInitPid(
     const base::FilePath& android_pid_file) {
   // This function does I/O and must be done on a blocking thread.
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
 
   std::string android_pid_contents;
   if (!base::ReadFileToString(android_pid_file, &android_pid_contents))
@@ -101,7 +101,7 @@
 base::Optional<ProcCpuUsageAndPpid> ComputeProcCpuTimeJiffiesAndPpid(
     const base::FilePath& proc_stat_file) {
   // This function does I/O and must be done on a blocking thread.
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
 
   base::Optional<system::SingleProcStat> stat =
       system::GetSingleProcStat(proc_stat_file);
@@ -115,7 +115,7 @@
 // Reads a process' name from |comm_file|, a file like "/proc/%u/comm".
 base::Optional<std::string> GetProcName(const base::FilePath& comm_file) {
   // This function does I/O and must be done on a blocking thread.
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
 
   std::string comm_contents;
   if (!base::ReadFileToString(comm_file, &comm_contents))
@@ -131,7 +131,7 @@
 // "/proc/%u/cmdline".
 base::Optional<std::string> GetProcCmdline(const base::FilePath& cmdline) {
   // This function does I/O and must be done on a blocking thread.
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
 
   std::string cmdline_contents;
   if (!base::ReadFileToString(cmdline, &cmdline_contents))
@@ -361,7 +361,7 @@
 ProcessDataCollector::ProcessSampleMap ProcessDataCollector::GetValidProcesses(
     const Config& config) {
   // This function does I/O and must be done on a blocking thread.
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
 
   base::FileEnumerator proc_files(config.proc_dir, false,
                                   base::FileEnumerator::DIRECTORIES);
diff --git a/chrome/browser/chromeos/smb_client/smb_file_system.cc b/chrome/browser/chromeos/smb_client/smb_file_system.cc
index 7ddb19e..d2c7302 100644
--- a/chrome/browser/chromeos/smb_client/smb_file_system.cc
+++ b/chrome/browser/chromeos/smb_client/smb_file_system.cc
@@ -102,6 +102,10 @@
 
 constexpr size_t kTaskQueueCapacity = 2;
 
+std::unique_ptr<TempFileManager> CreateTempFileManager() {
+  return std::make_unique<TempFileManager>();
+}
+
 }  // namespace
 
 using file_system_provider::AbortCallback;
@@ -375,7 +379,7 @@
     SmbTask task = base::BindOnce(
         base::IgnoreResult(&SmbFileSystem::CallWriteFile), AsWeakPtr(),
         file_handle, std::move(data), offset, length, std::move(callback));
-    InitTempFileManagerAndExecuteTask(std::move(task));
+    CreateTempFileManagerAndExecuteTask(std::move(task));
     // The call to init temp_file_manager_ will not be abortable since it is
     // asynchronous.
     return CreateAbortCallback();
@@ -384,17 +388,27 @@
   return CallWriteFile(file_handle, data, offset, length, std::move(callback));
 }
 
-void SmbFileSystem::InitTempFileManagerAndExecuteTask(SmbTask task) {
-  // InitTempFileManager() has to be called on a separate thread since it
+void SmbFileSystem::CreateTempFileManagerAndExecuteTask(SmbTask task) {
+  // CreateTempFileManager() has to be called on a separate thread since it
   // contains a call that requires a blockable thread.
   base::TaskTraits task_traits = {base::MayBlock(),
                                   base::TaskPriority::USER_BLOCKING,
                                   base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN};
-  base::OnceClosure init_task = base::BindOnce(
-      &SmbFileSystem::InitTempFileManager, base::Unretained(this));
+  auto init_task = base::BindOnce(&CreateTempFileManager);
+  auto reply = base::BindOnce(&SmbFileSystem::InitTempFileManagerAndExecuteTask,
+                              AsWeakPtr(), std::move(task));
+  base::PostTaskWithTraitsAndReplyWithResult(
+      FROM_HERE, task_traits, std::move(init_task), std::move(reply));
+}
 
-  base::PostTaskWithTraitsAndReply(FROM_HERE, task_traits, std::move(init_task),
-                                   std::move(task));
+void SmbFileSystem::InitTempFileManagerAndExecuteTask(
+    SmbTask task,
+    std::unique_ptr<TempFileManager> temp_file_manager) {
+  DCHECK(!temp_file_manager_);
+  DCHECK(temp_file_manager);
+
+  temp_file_manager_ = std::move(temp_file_manager);
+  std::move(task).Run();
 }
 
 AbortCallback SmbFileSystem::CallWriteFile(
@@ -715,11 +729,6 @@
   std::move(callback).Run(TranslateToFileError(error));
 }
 
-void SmbFileSystem::InitTempFileManager() {
-  DCHECK(!temp_file_manager_);
-  temp_file_manager_ = std::make_unique<TempFileManager>();
-}
-
 base::WeakPtr<file_system_provider::ProvidedFileSystemInterface>
 SmbFileSystem::GetWeakPtr() {
   return AsWeakPtr();
diff --git a/chrome/browser/chromeos/smb_client/smb_file_system.h b/chrome/browser/chromeos/smb_client/smb_file_system.h
index ce435e5..7050839 100644
--- a/chrome/browser/chromeos/smb_client/smb_file_system.h
+++ b/chrome/browser/chromeos/smb_client/smb_file_system.h
@@ -174,11 +174,14 @@
  private:
   void Abort(OperationId operation_id);
 
-  // Initializes temp_file_manager_.
-  void InitTempFileManager();
+  // Calls CreateTempFileManager() and executes |task|.
+  void CreateTempFileManagerAndExecuteTask(SmbTask task);
 
-  // Calls InitTempFileManager() and executes |task|.
-  void InitTempFileManagerAndExecuteTask(SmbTask task);
+  // Initializes |temp_file_manager_| with |temp_file_manager| and executes
+  // |task|.
+  void InitTempFileManagerAndExecuteTask(
+      SmbTask task,
+      std::unique_ptr<TempFileManager> temp_file_manager);
 
   // Calls WriteFile in SmbProviderClient.
   file_system_provider::AbortCallback CallWriteFile(
diff --git a/chrome/browser/chromeos/smb_client/smb_service.cc b/chrome/browser/chromeos/smb_client/smb_service.cc
index 9e29957..ad07a030 100644
--- a/chrome/browser/chromeos/smb_client/smb_service.cc
+++ b/chrome/browser/chromeos/smb_client/smb_service.cc
@@ -70,6 +70,10 @@
   UMA_HISTOGRAM_ENUMERATION("NativeSmbFileShare.RemountResult", result);
 }
 
+std::unique_ptr<TempFileManager> CreateTempFileManager() {
+  return std::make_unique<TempFileManager>();
+}
+
 }  // namespace
 
 bool SmbService::service_should_run_ = false;
@@ -258,10 +262,6 @@
   }
 }
 
-void SmbService::InitTempFileManager() {
-  temp_file_manager_ = std::make_unique<TempFileManager>();
-}
-
 void SmbService::StartSetup() {
   user_manager::User* user =
       chromeos::ProfileHelper::Get()->GetUserByProfile(profile_);
@@ -291,18 +291,16 @@
 }
 
 void SmbService::SetupTempFileManagerAndCompleteSetup() {
-  // InitTempFileManager() has to be called on a separate thread since it
+  // CreateTempFileManager() has to be called on a separate thread since it
   // contains a call that requires a blockable thread.
   base::TaskTraits task_traits = {base::MayBlock(),
                                   base::TaskPriority::USER_BLOCKING,
                                   base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN};
-  base::OnceClosure task =
-      base::BindOnce(&SmbService::InitTempFileManager, base::Unretained(this));
-  base::OnceClosure reply =
-      base::BindOnce(&SmbService::CompleteSetup, AsWeakPtr());
+  auto task = base::BindOnce(&CreateTempFileManager);
+  auto reply = base::BindOnce(&SmbService::CompleteSetup, AsWeakPtr());
 
-  base::PostTaskWithTraitsAndReply(FROM_HERE, task_traits, std::move(task),
-                                   std::move(reply));
+  base::PostTaskWithTraitsAndReplyWithResult(FROM_HERE, task_traits,
+                                             std::move(task), std::move(reply));
 }
 
 void SmbService::OnSetupKerberosResponse(bool success) {
@@ -313,7 +311,12 @@
   SetupTempFileManagerAndCompleteSetup();
 }
 
-void SmbService::CompleteSetup() {
+void SmbService::CompleteSetup(
+    std::unique_ptr<TempFileManager> temp_file_manager) {
+  DCHECK(temp_file_manager);
+  DCHECK(!temp_file_manager_);
+
+  temp_file_manager_ = std::move(temp_file_manager);
   share_finder_ = std::make_unique<SmbShareFinder>(GetSmbProviderClient());
   RegisterHostLocators();
 
diff --git a/chrome/browser/chromeos/smb_client/smb_service.h b/chrome/browser/chromeos/smb_client/smb_service.h
index b671801..eab3d9b 100644
--- a/chrome/browser/chromeos/smb_client/smb_service.h
+++ b/chrome/browser/chromeos/smb_client/smb_service.h
@@ -77,10 +77,7 @@
   void GatherSharesInNetwork(GatherSharesResponse callback);
 
  private:
-  // Initializes |temp_file_manager_|. Must be called on a non-ui thread.
-  void InitTempFileManager();
-
-  // Calls SmbProviderClient::Mount(). temp_file_manager_ must be initialized
+  // Calls SmbProviderClient::Mount(). |temp_file_manager_| must be initialized
   // before this is called.
   void CallMount(const file_system_provider::MountOptions& options,
                  const base::FilePath& share_path,
@@ -118,7 +115,7 @@
 
   // Completes SmbService setup including ShareFinder initialization and
   // remounting shares. Called by SetupTempFileManagerAndCompleteSetup().
-  void CompleteSetup();
+  void CompleteSetup(std::unique_ptr<TempFileManager> temp_file_manager);
 
   // Handles the response from attempting to setup Kerberos.
   void OnSetupKerberosResponse(bool success);
diff --git a/chrome/browser/chromeos/system/automatic_reboot_manager.cc b/chrome/browser/chromeos/system/automatic_reboot_manager.cc
index 9cf1c733..e2955019 100644
--- a/chrome/browser/chromeos/system/automatic_reboot_manager.cc
+++ b/chrome/browser/chromeos/system/automatic_reboot_manager.cc
@@ -25,7 +25,7 @@
 #include "base/posix/eintr_wrapper.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/task/post_task.h"
-#include "base/threading/thread_restrictions.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "base/time/tick_clock.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/chrome_notification_types.h"
@@ -53,7 +53,7 @@
 const int kOneKilobyte = 1 << 10;                  // 1 kB in bytes.
 
 base::TimeDelta ReadTimeDeltaFromFile(const base::FilePath& path) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   base::ScopedFD fd(
       HANDLE_EINTR(open(path.value().c_str(), O_RDONLY | O_NOFOLLOW)));
   if (!fd.is_valid())
@@ -85,7 +85,7 @@
 }
 
 void SaveUpdateRebootNeededUptime() {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   const base::TimeDelta kZeroTimeDelta;
 
   base::FilePath update_reboot_needed_uptime_file;
diff --git a/chrome/browser/extensions/active_tab_unittest.cc b/chrome/browser/extensions/active_tab_unittest.cc
index bbc87c4a..bb981db 100644
--- a/chrome/browser/extensions/active_tab_unittest.cc
+++ b/chrome/browser/extensions/active_tab_unittest.cc
@@ -46,6 +46,7 @@
 #if defined(OS_CHROMEOS)
 #include "base/run_loop.h"
 #include "chrome/browser/chromeos/extensions/active_tab_permission_granter_delegate_chromeos.h"
+#include "chrome/browser/chromeos/login/users/chrome_user_manager_impl.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/ui/ash/test_wallpaper_controller.h"
@@ -500,7 +501,79 @@
 }
 
 #if defined(OS_CHROMEOS)
-// Keep the unique_ptr around until callback has been run.
+class ActiveTabManagedSessionTest : public ActiveTabTest {
+ protected:
+  ActiveTabManagedSessionTest() {}
+
+  void SetUp() override {
+    ActiveTabTest::SetUp();
+
+    // Necessary to prevent instantiation of ProfileSyncService, which messes
+    // with our signin state below.
+    base::CommandLine::ForCurrentProcess()->AppendSwitch(
+        switches::kDisableSync);
+    // Necessary because no ProfileManager instance exists in this test.
+    base::CommandLine::ForCurrentProcess()->AppendSwitch(
+        chromeos::switches::kIgnoreUserProfileMappingForTests);
+
+    // Setup, login a public account user.
+    const std::string user_id = "public@account.user";
+    const std::string user_email = user_id;
+    const AccountId account_id =
+        AccountId::FromUserEmailGaiaId(user_email, user_id);
+    const std::string user_id_hash =
+        chromeos::ProfileHelper::Get()->GetUserIdHashByUserIdForTesting(
+            user_id);
+
+    local_state_ = std::make_unique<ScopedTestingLocalState>(
+        TestingBrowserProcess::GetGlobal());
+    wallpaper_controller_client_ =
+        std::make_unique<WallpaperControllerClient>();
+    wallpaper_controller_client_->InitForTesting(
+        test_wallpaper_controller_.CreateInterfacePtr());
+    g_browser_process->local_state()->SetString(
+        "PublicAccountPendingDataRemoval", user_email);
+    user_manager::UserManager::Get()->UserLoggedIn(account_id, user_id_hash,
+                                                   true /* browser_restart */,
+                                                   false /* is_child */);
+    // Finish initialization - some things are run as separate tasks.
+    base::RunLoop().RunUntilIdle();
+
+    google_ = GURL("http://www.google.com");
+    NavigateAndCommit(google_);
+  }
+
+  void TearDown() override {
+    // This one needs to be destructed here so it deregisters itself from
+    // CrosSettings before that is destructed down the line inside
+    // ChromeRenderViewHostTestHarness::TearDown.
+    wallpaper_controller_client_.reset();
+
+    chromeos::ChromeUserManagerImpl::ResetPublicAccountDelegatesForTesting();
+    chromeos::ChromeUserManager::Get()->Shutdown();
+
+    ActiveTabTest::TearDown();
+  }
+
+  std::unique_ptr<ScopedTestingLocalState> local_state_;
+  TestWallpaperController test_wallpaper_controller_;
+  std::unique_ptr<WallpaperControllerClient> wallpaper_controller_client_;
+  GURL google_;
+};
+
+// Test that there's no permission prompt in Managed Sessions (Public Sessions
+// v2) for activeTab.
+TEST_F(ActiveTabManagedSessionTest, NoPromptInManagedSession) {
+  chromeos::ScopedTestPublicSessionLoginState login_state(
+      chromeos::LoginState::LOGGED_IN_USER_PUBLIC_ACCOUNT_MANAGED);
+
+  active_tab_permission_granter()->GrantIfRequested(
+      extension_with_tab_capture.get());
+  EXPECT_TRUE(IsAllowed(extension_with_tab_capture, google_));
+}
+
+// Keep the unique_ptr around until callback has been run and don't forget to
+// unset the ActiveTabPermissionGranterDelegateChromeOS.
 std::unique_ptr<permission_helper::RequestResolvedCallback>
 QuitRunLoopOnRequestResolved(base::RunLoop* run_loop) {
   auto callback = std::make_unique<permission_helper::RequestResolvedCallback>(
@@ -512,57 +585,30 @@
   return callback;
 }
 
-// Test that the platform delegate is being set and the permission is prompted
-// for.
-TEST_F(ActiveTabTest, DelegateIsSet) {
-  // Necessary to prevent instantiation of ProfileSyncService, which messes with
-  // our signin state below.
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(switches::kDisableSync);
-  // Necessary because no ProfileManager instance exists in this test.
-  base::CommandLine::ForCurrentProcess()->AppendSwitch(
-      chromeos::switches::kIgnoreUserProfileMappingForTests);
-
-  // Setup, login a public account user.
-  chromeos::ScopedTestPublicSessionLoginState login_state;
-  std::string user_id = "public@account.user";
-  std::string user_email = user_id;
-  AccountId account_id = AccountId::FromUserEmailGaiaId(user_email, user_id);
-  std::string user_id_hash = chromeos::ProfileHelper::Get()->
-      GetUserIdHashByUserIdForTesting(user_id);
-  ScopedTestingLocalState local_state(TestingBrowserProcess::GetGlobal());
-  std::unique_ptr<WallpaperControllerClient> wallpaper_controller_client_ =
-      std::make_unique<WallpaperControllerClient>();
-  TestWallpaperController test_wallpaper_controller_;
-  wallpaper_controller_client_->InitForTesting(
-      test_wallpaper_controller_.CreateInterfacePtr());
-  g_browser_process->local_state()->SetString(
-      "PublicAccountPendingDataRemoval", user_email);
-  user_manager::UserManager::Get()->UserLoggedIn(account_id, user_id_hash,
-                                                 true /* browser_restart */,
-                                                 false /* is_child */);
-
-  GURL google("http://www.google.com");
-  NavigateAndCommit(google);
-
+// Test that the platform delegate is being set and the activeTab permission is
+// prompted for in Public Sessions.
+TEST_F(ActiveTabManagedSessionTest,
+       DelegateIsSetAndPromptIsShownInPublicSession) {
+  chromeos::ScopedTestPublicSessionLoginState login_state(
+      chromeos::LoginState::LOGGED_IN_USER_PUBLIC_ACCOUNT);
   // Grant and verify.
   {
     ScopedTestDialogAutoConfirm auto_confirm(
         ScopedTestDialogAutoConfirm::ACCEPT);
 
+    // RunLoop needed to resolve the permission dialog.
     base::RunLoop run_loop;
     auto cb = QuitRunLoopOnRequestResolved(&run_loop);
     active_tab_permission_granter()->GrantIfRequested(extension.get());
     run_loop.Run();
-    EXPECT_TRUE(IsBlocked(extension, google));
+    EXPECT_TRUE(IsBlocked(extension, google_));
 
-    base::RunLoop run_loop2;
-    cb = QuitRunLoopOnRequestResolved(&run_loop2);
     active_tab_permission_granter()->GrantIfRequested(extension.get());
-    run_loop2.Run();
-    EXPECT_TRUE(IsAllowed(extension, google));
+    EXPECT_TRUE(IsAllowed(extension, google_));
   }
 
-  // Deny and verify. Use a different extension so it doesn't trigger the cache.
+  // Deny and verify. Use a different extension so it doesn't trigger the
+  // cache.
   {
     ScopedTestDialogAutoConfirm auto_confirm(
         ScopedTestDialogAutoConfirm::CANCEL);
@@ -571,20 +617,15 @@
     auto cb = QuitRunLoopOnRequestResolved(&run_loop);
     active_tab_permission_granter()->GrantIfRequested(another_extension.get());
     run_loop.Run();
-    EXPECT_TRUE(IsBlocked(another_extension, google));
+    EXPECT_TRUE(IsBlocked(another_extension, google_));
 
-    base::RunLoop run_loop2;
-    cb = QuitRunLoopOnRequestResolved(&run_loop2);
     active_tab_permission_granter()->GrantIfRequested(another_extension.get());
-    run_loop2.Run();
-    EXPECT_TRUE(IsBlocked(another_extension, google));
+    EXPECT_TRUE(IsBlocked(another_extension, google_));
   }
 
   // Cleanup.
   ActiveTabPermissionGranterDelegateChromeOS::
       SetRequestResolvedCallbackForTesting(nullptr);
-  delete ActiveTabPermissionGranter::SetPlatformDelegate(nullptr);
-  chromeos::ChromeUserManager::Get()->Shutdown();
 }
 #endif  // defined(OS_CHROMEOS)
 
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.cc b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
index 2a4dc7a..ca12fc5 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.cc
@@ -493,6 +493,12 @@
   BroadcastItemStateChanged(developer::EVENT_TYPE_PREFS_CHANGED, extension_id);
 }
 
+void DeveloperPrivateEventRouter::OnExtensionRuntimePermissionsChanged(
+    const std::string& extension_id) {
+  BroadcastItemStateChanged(developer::EVENT_TYPE_PERMISSIONS_CHANGED,
+                            extension_id);
+}
+
 void DeveloperPrivateEventRouter::OnExtensionManagementSettingsChanged() {
   std::unique_ptr<base::ListValue> args(new base::ListValue());
   args->Append(CreateProfileInfo(profile_)->ToValue());
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api.h b/chrome/browser/extensions/api/developer_private/developer_private_api.h
index 8edc8cc..373a430 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api.h
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api.h
@@ -110,6 +110,8 @@
   // ExtensionPrefsObserver:
   void OnExtensionDisableReasonsChanged(const std::string& extension_id,
                                         int disable_reasons) override;
+  void OnExtensionRuntimePermissionsChanged(
+      const std::string& extension_id) override;
 
   // ExtensionManagement::Observer:
   void OnExtensionManagementSettingsChanged() override;
diff --git a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
index 17d2e80..9caa8e0 100644
--- a/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
+++ b/chrome/browser/extensions/api/developer_private/developer_private_api_unittest.cc
@@ -96,6 +96,34 @@
   return has_pref(id, context);
 }
 
+bool WasPermissionsUpdatedEventDispatched(
+    const TestEventRouterObserver& observer,
+    const ExtensionId& extension_id) {
+  const std::string kEventName =
+      api::developer_private::OnItemStateChanged::kEventName;
+  const auto& event_map = observer.events();
+  auto iter = event_map.find(kEventName);
+  if (iter == event_map.end())
+    return false;
+
+  const Event& event = *iter->second;
+  CHECK(event.event_args);
+  CHECK_GE(1u, event.event_args->GetList().size());
+  std::unique_ptr<api::developer_private::EventData> event_data =
+      api::developer_private::EventData::FromValue(
+          event.event_args->GetList()[0]);
+  if (!event_data)
+    return false;
+
+  if (event_data->item_id != extension_id ||
+      event_data->event_type !=
+          api::developer_private::EVENT_TYPE_PERMISSIONS_CHANGED) {
+    return false;
+  }
+
+  return true;
+}
+
 }  // namespace
 
 class DeveloperPrivateApiUnitTest : public ExtensionServiceTestWithInstall {
@@ -1605,11 +1633,65 @@
             *extension_prefs->GetRuntimeGrantedPermissions(extension->id()));
 }
 
-TEST_F(DeveloperPrivateApiUnitTest, ExtensionUpdatedEventOnPermissionsChange) {
+TEST_F(DeveloperPrivateApiUnitTest,
+       UpdateHostAccess_UnrequestedHostsDispatchUpdateEvents) {
+  base::test::ScopedFeatureList feature_list;
+  feature_list.InitAndEnableFeature(
+      extensions_features::kRuntimeHostPermissions);
+
+  scoped_refptr<const Extension> extension =
+      ExtensionBuilder("test").AddPermission("http://google.com/*").Build();
+  service()->AddExtension(extension.get());
+  ScriptingPermissionsModifier modifier(profile(), extension.get());
+  modifier.SetWithholdHostPermissions(true);
+
+  // We need to call DeveloperPrivateAPI::Get() in order to instantiate the
+  // keyed service, since it's not created by default in unit tests.
   DeveloperPrivateAPI::Get(profile());
   const ExtensionId listener_id = crx_file::id_util::GenerateId("listener");
   EventRouter* event_router = EventRouter::Get(profile());
 
+  // The DeveloperPrivateEventRouter will only dispatch events if there's at
+  // least one listener to dispatch to. Create one.
+  content::RenderProcessHost* process = nullptr;
+  const char* kEventName =
+      api::developer_private::OnItemStateChanged::kEventName;
+  event_router->AddEventListener(kEventName, process, listener_id);
+
+  TestEventRouterObserver test_observer(event_router);
+  EXPECT_FALSE(
+      WasPermissionsUpdatedEventDispatched(test_observer, extension->id()));
+
+  URLPatternSet hosts({URLPattern(Extension::kValidHostPermissionSchemes,
+                                  "https://example.com/*")});
+  PermissionSet permissions(APIPermissionSet(), ManifestPermissionSet(), hosts,
+                            hosts);
+  PermissionsUpdater(profile()).GrantRuntimePermissions(*extension,
+                                                        permissions);
+  // The event router fetches icons from a blocking thread when sending the
+  // update event; allow it to finish before verifying the event was dispatched.
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(
+      WasPermissionsUpdatedEventDispatched(test_observer, extension->id()));
+
+  test_observer.ClearEvents();
+
+  PermissionsUpdater(profile()).RevokeRuntimePermissions(*extension,
+                                                         permissions);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_TRUE(
+      WasPermissionsUpdatedEventDispatched(test_observer, extension->id()));
+}
+
+TEST_F(DeveloperPrivateApiUnitTest, ExtensionUpdatedEventOnPermissionsChange) {
+  // We need to call DeveloperPrivateAPI::Get() in order to instantiate the
+  // keyed service, since it's not created by default in unit tests.
+  DeveloperPrivateAPI::Get(profile());
+  const ExtensionId listener_id = crx_file::id_util::GenerateId("listener");
+  EventRouter* event_router = EventRouter::Get(profile());
+
+  // The DeveloperPrivateEventRouter will only dispatch events if there's at
+  // least one listener to dispatch to. Create one.
   content::RenderProcessHost* process = nullptr;
   const char* kEventName =
       api::developer_private::OnItemStateChanged::kEventName;
@@ -1622,31 +1704,8 @@
           .Build();
 
   TestEventRouterObserver test_observer(event_router);
-  auto dispatched_updated_event = [&test_observer, kEventName,
-                                   &dummy_extension]() {
-    const auto& event_map = test_observer.events();
-    auto iter = event_map.find(kEventName);
-    if (iter == event_map.end())
-      return false;
-
-    const Event& event = *iter->second;
-    CHECK(event.event_args);
-    CHECK_GE(1u, event.event_args->GetList().size());
-    std::unique_ptr<api::developer_private::EventData> event_data =
-        api::developer_private::EventData::FromValue(
-            event.event_args->GetList()[0]);
-    if (!event_data)
-      return false;
-
-    if (event_data->item_id != dummy_extension->id() ||
-        event_data->event_type !=
-            api::developer_private::EVENT_TYPE_PERMISSIONS_CHANGED) {
-      return false;
-    }
-
-    return true;
-  };
-  EXPECT_FALSE(dispatched_updated_event());
+  EXPECT_FALSE(WasPermissionsUpdatedEventDispatched(test_observer,
+                                                    dummy_extension->id()));
 
   APIPermissionSet apis;
   apis.insert(APIPermission::kTab);
@@ -1654,15 +1713,19 @@
                             URLPatternSet());
   PermissionsUpdater(profile()).GrantOptionalPermissions(*dummy_extension,
                                                          permissions);
+  // The event router fetches icons from a blocking thread when sending the
+  // update event; allow it to finish before verifying the event was dispatched.
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(dispatched_updated_event());
+  EXPECT_TRUE(WasPermissionsUpdatedEventDispatched(test_observer,
+                                                   dummy_extension->id()));
 
   test_observer.ClearEvents();
 
   PermissionsUpdater(profile()).RevokeOptionalPermissions(
       *dummy_extension, permissions, PermissionsUpdater::REMOVE_HARD);
   base::RunLoop().RunUntilIdle();
-  EXPECT_TRUE(dispatched_updated_event());
+  EXPECT_TRUE(WasPermissionsUpdatedEventDispatched(test_observer,
+                                                   dummy_extension->id()));
 }
 
 class DeveloperPrivateZipInstallerUnitTest
diff --git a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
index e0fbac6..ca24204 100644
--- a/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
+++ b/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc
@@ -56,6 +56,7 @@
 #include "content/public/test/test_utils.h"
 #include "extensions/browser/event_router.h"
 #include "extensions/browser/notification_types.h"
+#include "extensions/common/manifest_handlers/incognito_info.h"
 #include "net/base/data_url.h"
 #include "net/dns/mock_host_resolver.h"
 #include "net/test/embedded_test_server/controllable_http_response.h"
@@ -659,11 +660,13 @@
  private:
   void SetUpExtensionFunction(UIThreadExtensionFunction* function) {
     if (extension_) {
+      const GURL url = current_browser_ == incognito_browser_ &&
+                               !IncognitoInfo::IsSplitMode(extension_)
+                           ? GURL(url::kAboutBlankURL)
+                           : extension_->GetResourceURL("empty.html");
       // Recreate the tab each time for insulation.
       content::WebContents* tab = chrome::AddSelectedTabWithURL(
-          current_browser(),
-          extension_->GetResourceURL("empty.html"),
-          ui::PAGE_TRANSITION_LINK);
+          current_browser(), url, ui::PAGE_TRANSITION_LINK);
       function->set_extension(extension_);
       function->SetRenderFrameHost(tab->GetMainFrame());
     }
diff --git a/chrome/browser/extensions/api/media_perception_private/media_perception_api_delegate_chromeos.cc b/chrome/browser/extensions/api/media_perception_private/media_perception_api_delegate_chromeos.cc
index 2afcbe9c..b5542d7 100644
--- a/chrome/browser/extensions/api/media_perception_private/media_perception_api_delegate_chromeos.cc
+++ b/chrome/browser/extensions/api/media_perception_private/media_perception_api_delegate_chromeos.cc
@@ -11,7 +11,9 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/component_updater/cros_component_installer_chromeos.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/delegate_to_browser_gpu_service_accelerator_factory.h"
 #include "content/public/common/service_manager_connection.h"
+#include "mojo/public/cpp/bindings/strong_binding.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/video_capture/public/mojom/constants.mojom.h"
 #include "services/video_capture/public/mojom/device_factory.mojom.h"
@@ -78,6 +80,13 @@
   if (!connector)
     return;
   connector->BindInterface(video_capture::mojom::kServiceName, provider);
+
+  video_capture::mojom::AcceleratorFactoryPtr accelerator_factory;
+  mojo::MakeStrongBinding(
+      std::make_unique<
+          content::DelegateToBrowserGpuServiceAcceleratorFactory>(),
+      mojo::MakeRequest(&accelerator_factory));
+  (*provider)->InjectGpuDependencies(std::move(accelerator_factory));
 }
 
 }  // namespace extensions
diff --git a/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc b/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc
index 9cea81a..8020fe8 100644
--- a/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc
+++ b/chrome/browser/extensions/cross_origin_read_blocking_browsertest.cc
@@ -44,17 +44,37 @@
   }
 
  protected:
-  void InstallExtension() {
-    const char kManifest[] = R"(
+  void InstallExtension(
+      GURL resource_to_fetch_from_declarative_content_script = GURL()) {
+    bool use_declarative_content_script =
+        resource_to_fetch_from_declarative_content_script.is_valid();
+
+    const char kContentScriptManifestEntry[] = R"(
+          "content_scripts": [{
+            "matches": ["*://*/*"],
+            "js": ["content_script.js"]
+          }],
+    )";
+    const char kManifestTemplate[] = R"(
         {
           "name": "CrossOriginReadBlockingTest",
           "version": "1.0",
           "manifest_version": 2,
           "permissions": ["tabs", "*://*/*"],
-          "background": {"scripts": ["script.js"]}
+          %s
+          "background": {"scripts": ["background_script.js"]}
         } )";
-    dir_.WriteManifest(kManifest);
-    dir_.WriteFile(FILE_PATH_LITERAL("script.js"), "");
+    dir_.WriteManifest(base::StringPrintf(
+        kManifestTemplate,
+        use_declarative_content_script ? kContentScriptManifestEntry : ""));
+
+    dir_.WriteFile(FILE_PATH_LITERAL("background_script.js"), "");
+
+    if (use_declarative_content_script) {
+      dir_.WriteFile(
+          FILE_PATH_LITERAL("content_script.js"),
+          CreateFetchScript(resource_to_fetch_from_declarative_content_script));
+    }
     extension_ = LoadExtension(dir_.UnpackedPath());
   }
 
@@ -94,6 +114,16 @@
     VerifyContentScriptHistogram(histograms, testing::IsEmpty());
   }
 
+  std::string PopString(content::DOMMessageQueue* message_queue) {
+    std::string json;
+    EXPECT_TRUE(message_queue->WaitForMessage(&json));
+    base::JSONReader reader(base::JSON_ALLOW_TRAILING_COMMAS);
+    std::unique_ptr<base::Value> value = reader.ReadToValue(json);
+    std::string result;
+    EXPECT_TRUE(value->GetAsString(&result));
+    return result;
+  }
+
  private:
   // Asks the test |extension_| to inject |content_script| into |web_contents|.
   // Returns true if the content script injection succeeded.
@@ -106,29 +136,26 @@
         browser()->profile(), extension_->id(), background_script);
   }
 
-  using FetchCallback =
-      base::OnceCallback<bool(const std::string& fetch_script)>;
-  std::string FetchHelper(GURL url, FetchCallback fetch_callback) {
-    content::DOMMessageQueue message_queue;
-
-    // Inject a content script that performs a cross-origin XHR to bar.com.
+  std::string CreateFetchScript(const GURL& resource) {
     const char kXhrScriptTemplate[] = R"(
       fetch($1)
         .then(response => response.text())
         .then(text => domAutomationController.send(text))
         .catch(err => domAutomationController.send("error: " + err));
     )";
-    EXPECT_TRUE(std::move(fetch_callback)
-                    .Run(content::JsReplace(kXhrScriptTemplate, url.spec())));
+    return content::JsReplace(kXhrScriptTemplate, resource);
+  }
+
+  using FetchCallback =
+      base::OnceCallback<bool(const std::string& fetch_script)>;
+  std::string FetchHelper(GURL url, FetchCallback fetch_callback) {
+    content::DOMMessageQueue message_queue;
+
+    // Inject a content script that performs a cross-origin XHR to bar.com.
+    EXPECT_TRUE(std::move(fetch_callback).Run(CreateFetchScript(url)));
 
     // Wait until the message comes back and extract result from the message.
-    std::string json;
-    EXPECT_TRUE(message_queue.WaitForMessage(&json));
-    base::JSONReader reader(base::JSON_ALLOW_TRAILING_COMMAS);
-    std::unique_ptr<base::Value> value = reader.ReadToValue(json);
-    std::string result;
-    EXPECT_TRUE(value->GetAsString(&result));
-    return result;
+    return PopString(&message_queue);
   }
 
   void VerifyContentScriptHistogram(
@@ -157,12 +184,43 @@
   DISALLOW_COPY_AND_ASSIGN(CrossOriginReadBlockingExtensionTest);
 };
 
+IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest,
+                       FromDeclarativeContentScript_NoSniffXml) {
+  // Load the test extension.
+  GURL cross_site_resource(
+      embedded_test_server()->GetURL("bar.com", "/nosniff.xml"));
+  InstallExtension(cross_site_resource);
+
+  // Navigate to a foo.com page - this should trigger execution of the
+  // |content_script| declared in the extension manifest.
+  base::HistogramTester histograms;
+  content::DOMMessageQueue message_queue;
+  content::WebContents* web_contents =
+      browser()->tab_strip_model()->GetActiveWebContents();
+  GURL page_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
+  ui_test_utils::NavigateToURL(browser(), page_url);
+  EXPECT_EQ(page_url, web_contents->GetMainFrame()->GetLastCommittedURL());
+  EXPECT_EQ(url::Origin::Create(page_url),
+            web_contents->GetMainFrame()->GetLastCommittedOrigin());
+
+  // Extract results of the fetch done in the declarative content script.
+  std::string fetch_result = PopString(&message_queue);
+
+  // Verify that no blocking occurred.
+  EXPECT_EQ("nosniff.xml - body\n", fetch_result);
+  EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.Browser.Blocked"),
+              testing::IsEmpty());
+
+  // Verify that LogInitiatorSchemeBypassingDocumentBlocking was called.
+  VerifyContentScriptHistogramIsPresent(histograms, content::RESOURCE_TYPE_XHR);
+}
+
 // Test that verifies the current, baked-in (but not necessarily desirable
 // behavior) where an extension that has permission to inject a content script
 // to any page can also XHR (without CORS!) any cross-origin resource.
 // See also https://crbug.com/846346.
 IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest,
-                       FromContentScript_NoSniffXml) {
+                       FromProgrammaticContentScript_NoSniffXml) {
   // Load the test extension.
   InstallExtension();
 
@@ -179,10 +237,11 @@
   base::HistogramTester histograms;
   GURL cross_site_resource(
       embedded_test_server()->GetURL("bar.com", "/nosniff.xml"));
-  EXPECT_EQ("nosniff.xml - body\n",
-            FetchViaContentScript(cross_site_resource, web_contents));
+  std::string fetch_result =
+      FetchViaContentScript(cross_site_resource, web_contents);
 
   // Verify that no blocking occurred.
+  EXPECT_EQ("nosniff.xml - body\n", fetch_result);
   EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.Browser.Blocked"),
               testing::IsEmpty());
 
@@ -193,7 +252,7 @@
 // Test that responses that would have been allowed by CORB anyway are not
 // reported to LogInitiatorSchemeBypassingDocumentBlocking.
 IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest,
-                       FromContentScript_AllowedTextResource) {
+                       FromProgrammaticContentScript_AllowedTextResource) {
   // Load the test extension.
   InstallExtension();
 
@@ -213,11 +272,13 @@
   base::HistogramTester histograms;
   GURL cross_site_resource(
       embedded_test_server()->GetURL("bar.com", "/save_page/text.txt"));
-  EXPECT_THAT(FetchViaContentScript(cross_site_resource, web_contents),
-              ::testing::StartsWith(
-                  "text-object.txt: ae52dd09-9746-4b7e-86a6-6ada5e2680c2"));
+  std::string fetch_result =
+      FetchViaContentScript(cross_site_resource, web_contents);
 
   // Verify that no blocking occurred.
+  EXPECT_THAT(fetch_result,
+              ::testing::StartsWith(
+                  "text-object.txt: ae52dd09-9746-4b7e-86a6-6ada5e2680c2"));
   EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.Browser.Blocked"),
               testing::IsEmpty());
 
@@ -229,7 +290,7 @@
 // Test that responses are blocked by CORB, but have empty response body are not
 // reported to LogInitiatorSchemeBypassingDocumentBlocking.
 IN_PROC_BROWSER_TEST_F(CrossOriginReadBlockingExtensionTest,
-                       FromContentScript_EmptyAndBlocked) {
+                       FromProgrammaticContentScript_EmptyAndBlocked) {
   // Load the test extension.
   InstallExtension();
 
@@ -268,10 +329,10 @@
   base::HistogramTester histograms;
   GURL cross_site_resource(
       embedded_test_server()->GetURL("bar.com", "/nosniff.xml"));
-  EXPECT_EQ("nosniff.xml - body\n",
-            FetchViaBackgroundPage(cross_site_resource));
+  std::string fetch_result = FetchViaBackgroundPage(cross_site_resource);
 
   // Verify that no blocking occurred.
+  EXPECT_EQ("nosniff.xml - body\n", fetch_result);
   EXPECT_THAT(histograms.GetAllSamples("SiteIsolation.XSD.Browser.Blocked"),
               testing::IsEmpty());
 
diff --git a/chrome/browser/extensions/extension_tab_util.cc b/chrome/browser/extensions/extension_tab_util.cc
index ffe7979..a5778d0 100644
--- a/chrome/browser/extensions/extension_tab_util.cc
+++ b/chrome/browser/extensions/extension_tab_util.cc
@@ -489,11 +489,14 @@
 }
 
 // static
-void ExtensionTabUtil::SetPlatformDelegate(Delegate* delegate) {
+ExtensionTabUtil::Delegate* ExtensionTabUtil::SetPlatformDelegate(
+    Delegate* delegate) {
   // Allow setting it only once (also allow reset to nullptr, but then take
   // special care to free it).
   CHECK(!g_extension_tab_util_delegate || !delegate);
+  Delegate* previous_delegate = g_extension_tab_util_delegate;
   g_extension_tab_util_delegate = delegate;
+  return previous_delegate;
 }
 
 // static
diff --git a/chrome/browser/extensions/extension_tab_util.h b/chrome/browser/extensions/extension_tab_util.h
index 0be4ae2..c11fa02 100644
--- a/chrome/browser/extensions/extension_tab_util.h
+++ b/chrome/browser/extensions/extension_tab_util.h
@@ -135,8 +135,8 @@
 
   // Platform specific logic moved to delegate. This should be set during
   // startup.
-  // |delegate| is a singleton instance and is leaked.
-  static void SetPlatformDelegate(Delegate* delegate);
+  // |delegate| is never deleted by this class.
+  static Delegate* SetPlatformDelegate(Delegate* delegate);
 
   // Removes any privacy-sensitive fields from a Tab object if appropriate,
   // given the permissions of the extension and the tab in question.  The
diff --git a/chrome/browser/extensions/permissions_updater.cc b/chrome/browser/extensions/permissions_updater.cc
index b663743..6ec0994 100644
--- a/chrome/browser/extensions/permissions_updater.cc
+++ b/chrome/browser/extensions/permissions_updater.cc
@@ -88,11 +88,14 @@
 PermissionsUpdater::~PermissionsUpdater() {}
 
 // static
-void PermissionsUpdater::SetPlatformDelegate(Delegate* delegate) {
+PermissionsUpdater::Delegate* PermissionsUpdater::SetPlatformDelegate(
+    Delegate* delegate) {
   // Make sure we're setting it only once (allow setting to nullptr, but then
   // take special care of actually freeing it).
   CHECK(!g_delegate || !delegate);
+  Delegate* previous_delegate = g_delegate;
   g_delegate = delegate;
+  return previous_delegate;
 }
 
 void PermissionsUpdater::GrantOptionalPermissions(
diff --git a/chrome/browser/extensions/permissions_updater.h b/chrome/browser/extensions/permissions_updater.h
index 8bbeca4..702ac85 100644
--- a/chrome/browser/extensions/permissions_updater.h
+++ b/chrome/browser/extensions/permissions_updater.h
@@ -65,7 +65,7 @@
   // during startup (to ensure all extensions are initialized through the
   // delegate).
   // |delegate| is a singleton instance and is leaked.
-  static void SetPlatformDelegate(Delegate* delegate);
+  static Delegate* SetPlatformDelegate(Delegate* delegate);
 
   // Grants |permissions| that were defined as optional in the manifest to
   // |extension|, updating the active permission set and notifying any
diff --git a/chrome/browser/extensions/scripting_permissions_modifier.cc b/chrome/browser/extensions/scripting_permissions_modifier.cc
index faae589..45fe491 100644
--- a/chrome/browser/extensions/scripting_permissions_modifier.cc
+++ b/chrome/browser/extensions/scripting_permissions_modifier.cc
@@ -150,13 +150,15 @@
   if (HasWithheldHostPermissions() == should_withhold)
     return;
 
+  // Set the pref first, so that listeners for permission changes get the proper
+  // value if they query HasWithheldHostPermissions().
+  SetWithholdPermissionsPrefValue(extension_prefs_, extension_->id(),
+                                  should_withhold);
+
   if (should_withhold)
     WithholdHostPermissions();
   else
     GrantWithheldHostPermissions();
-
-  SetWithholdPermissionsPrefValue(extension_prefs_, extension_->id(),
-                                  should_withhold);
 }
 
 bool ScriptingPermissionsModifier::HasWithheldHostPermissions() const {
diff --git a/chrome/browser/local_discovery/service_discovery_shared_client.cc b/chrome/browser/local_discovery/service_discovery_shared_client.cc
index f87b1e9..2fb0121 100644
--- a/chrome/browser/local_discovery/service_discovery_shared_client.cc
+++ b/chrome/browser/local_discovery/service_discovery_shared_client.cc
@@ -16,7 +16,6 @@
 #include "base/path_service.h"
 #include "base/task/post_task.h"
 #include "base/timer/elapsed_timer.h"
-#include "chrome/installer/util/browser_distribution.h"
 #include "chrome/installer/util/firewall_manager_win.h"
 #endif
 
@@ -41,9 +40,7 @@
   if (!base::PathService::Get(base::FILE_EXE, &exe_path))
     return;
   base::ElapsedTimer timer;
-  std::unique_ptr<installer::FirewallManager> manager =
-      installer::FirewallManager::Create(BrowserDistribution::GetDistribution(),
-                                         exe_path);
+  auto manager = installer::FirewallManager::Create(exe_path);
   if (!manager)
     return;
   bool is_firewall_ready = manager->CanUseLocalPorts();
diff --git a/chrome/browser/media/router/mojo/media_route_provider_util_win.cc b/chrome/browser/media/router/mojo/media_route_provider_util_win.cc
index 2666ce9..f8a64eb2 100644
--- a/chrome/browser/media/router/mojo/media_route_provider_util_win.cc
+++ b/chrome/browser/media/router/mojo/media_route_provider_util_win.cc
@@ -10,7 +10,6 @@
 #include "base/path_service.h"
 #include "base/task/post_task.h"
 #include "base/task_runner_util.h"
-#include "chrome/installer/util/browser_distribution.h"
 #include "chrome/installer/util/firewall_manager_win.h"
 
 namespace media_router {
@@ -23,8 +22,7 @@
     LOG(WARNING) << "Couldn't get path of current executable.";
     return false;
   }
-  auto firewall_manager = installer::FirewallManager::Create(
-      BrowserDistribution::GetDistribution(), exe_path);
+  auto firewall_manager = installer::FirewallManager::Create(exe_path);
   if (!firewall_manager) {
     LOG(WARNING) << "Couldn't get FirewallManager instance.";
     return false;
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
index 2bea92300..940efb6 100644
--- a/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
+++ b/chrome/browser/media/router/mojo/media_router_mojo_impl.cc
@@ -1008,6 +1008,16 @@
   }
 }
 
+void MediaRouterMojoImpl::GetMirroringServiceHostForOffscreenTab(
+    const GURL& presentation_url,
+    const std::string& presentation_id,
+    mirroring::mojom::MirroringServiceHostRequest request) {
+  if (ShouldUseMirroringService() && IsValidPresentationUrl(presentation_url)) {
+    mirroring::CastMirroringServiceHost::GetForOffscreenTab(
+        context_, presentation_url, presentation_id, std::move(request));
+  }
+}
+
 void MediaRouterMojoImpl::BindToMojoRequest(
     mojo::InterfaceRequest<mojom::MediaRouter> request) {
   bindings_.AddBinding(this, std::move(request));
diff --git a/chrome/browser/media/router/mojo/media_router_mojo_impl.h b/chrome/browser/media/router/mojo/media_router_mojo_impl.h
index 07f78a5..b552f84 100644
--- a/chrome/browser/media/router/mojo/media_router_mojo_impl.h
+++ b/chrome/browser/media/router/mojo/media_router_mojo_impl.h
@@ -363,6 +363,10 @@
       int32_t initiator_tab_id,
       const std::string& desktop_stream_id,
       mirroring::mojom::MirroringServiceHostRequest request) override;
+  void GetMirroringServiceHostForOffscreenTab(
+      const GURL& presentation_url,
+      const std::string& presentation_id,
+      mirroring::mojom::MirroringServiceHostRequest request) override;
 
   // Result callback when Mojo TerminateRoute is invoked.
   // |route_id|: ID of MediaRoute passed to the TerminateRoute request.
diff --git a/chrome/browser/media/router/test/mock_mojo_media_router.h b/chrome/browser/media/router/test/mock_mojo_media_router.h
index 878f28b3..8499e5f1 100644
--- a/chrome/browser/media/router/test/mock_mojo_media_router.h
+++ b/chrome/browser/media/router/test/mock_mojo_media_router.h
@@ -82,6 +82,10 @@
                void(int32_t initiator_tab_id,
                     const std::string& desktop_stream_id,
                     mirroring::mojom::MirroringServiceHostRequest request));
+  MOCK_METHOD3(GetMirroringServiceHostForOffscreenTab,
+               void(const GURL& presentation_url,
+                    const std::string& presentation_id,
+                    mirroring::mojom::MirroringServiceHostRequest request));
 };
 
 }  // namespace media_router
diff --git a/chrome/browser/metrics/metrics_reporting_state.h b/chrome/browser/metrics/metrics_reporting_state.h
index 06893c2..944c713 100644
--- a/chrome/browser/metrics/metrics_reporting_state.h
+++ b/chrome/browser/metrics/metrics_reporting_state.h
@@ -18,7 +18,7 @@
 // stops the metrics service based on the new state and then runs |callback_fn|
 // (which can be null) with the updated state (as the operation may fail). On
 // platforms other than CrOS and Android, also updates the underlying pref.
-// TODO(gayane): Support setting the pref on all platforms.
+// TODO(https://crbug.com/880936): Support setting the pref on all platforms.
 void ChangeMetricsReportingStateWithReply(
     bool enabled,
     const OnMetricsReportingCallbackType& callback_fn);
diff --git a/chrome/browser/metrics/ukm_browsertest.cc b/chrome/browser/metrics/ukm_browsertest.cc
index 399b1b7..77b7181 100644
--- a/chrome/browser/metrics/ukm_browsertest.cc
+++ b/chrome/browser/metrics/ukm_browsertest.cc
@@ -871,7 +871,7 @@
   uint64_t original_client_id = client_id();
   EXPECT_NE(0U, original_client_id);
 
-  harness->SignoutSyncService();
+  harness->SignOutPrimaryAccount();
   EXPECT_FALSE(ukm_enabled());
   EXPECT_NE(original_client_id, client_id());
 
@@ -903,7 +903,7 @@
   EXPECT_TRUE(ukm_enabled());
   EXPECT_EQ(original_client_id, client_id());
 
-  harness2->SignoutSyncService();
+  harness2->SignOutPrimaryAccount();
   EXPECT_FALSE(ukm_enabled());
   EXPECT_NE(original_client_id, client_id());
 
diff --git a/chrome/browser/net/system_network_context_manager.cc b/chrome/browser/net/system_network_context_manager.cc
index 3e5e84c..31bd332 100644
--- a/chrome/browser/net/system_network_context_manager.cc
+++ b/chrome/browser/net/system_network_context_manager.cc
@@ -124,7 +124,7 @@
   }
 
   *stub_resolver_enabled =
-      !!dns_over_https_servers ||
+      dns_over_https_servers->has_value() ||
       local_state->GetBoolean(prefs::kBuiltInDnsClientEnabled);
 }
 
diff --git a/chrome/browser/notifications/notification_platform_bridge_android.cc b/chrome/browser/notifications/notification_platform_bridge_android.cc
index 1adaea5..1c7e778 100644
--- a/chrome/browser/notifications/notification_platform_bridge_android.cc
+++ b/chrome/browser/notifications/notification_platform_bridge_android.cc
@@ -25,9 +25,9 @@
 #include "components/pref_registry/pref_registry_syncable.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/persistent_notification_status.h"
-#include "content/public/common/platform_notification_data.h"
 #include "jni/ActionInfo_jni.h"
 #include "jni/NotificationPlatformBridge_jni.h"
+#include "third_party/blink/public/common/notifications/platform_notification_data.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/android/java_bitmap.h"
 #include "ui/gfx/image/image.h"
diff --git a/chrome/browser/notifications/persistent_notification_handler_unittest.cc b/chrome/browser/notifications/persistent_notification_handler_unittest.cc
index e7e3aba..35900f1 100644
--- a/chrome/browser/notifications/persistent_notification_handler_unittest.cc
+++ b/chrome/browser/notifications/persistent_notification_handler_unittest.cc
@@ -15,12 +15,12 @@
 #include "chrome/browser/notifications/platform_notification_service_impl.h"
 #include "chrome/test/base/testing_profile.h"
 #include "content/public/browser/permission_type.h"
-#include "content/public/common/notification_resources.h"
 #include "content/public/common/persistent_notification_status.h"
 #include "content/public/test/mock_permission_manager.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/notifications/notification_resources.h"
 #include "third_party/blink/public/platform/modules/permissions/permission_status.mojom.h"
 
 using ::testing::_;
@@ -118,11 +118,10 @@
     EXPECT_CALL(*mock_logger_, LogPersistentNotificationShown());
 
     PlatformNotificationServiceImpl::GetInstance()
-        ->DisplayPersistentNotification(&profile_, kExampleNotificationId,
-                                        origin_ /* service_worker_scope */,
-                                        origin_,
-                                        content::PlatformNotificationData(),
-                                        content::NotificationResources());
+        ->DisplayPersistentNotification(
+            &profile_, kExampleNotificationId,
+            origin_ /* service_worker_scope */, origin_,
+            blink::PlatformNotificationData(), blink::NotificationResources());
 
     run_loop.Run();
   }
diff --git a/chrome/browser/notifications/platform_notification_service_impl.cc b/chrome/browser/notifications/platform_notification_service_impl.cc
index 55d5df6..e627337 100644
--- a/chrome/browser/notifications/platform_notification_service_impl.cc
+++ b/chrome/browser/notifications/platform_notification_service_impl.cc
@@ -35,10 +35,10 @@
 #include "components/prefs/pref_registry_simple.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_thread.h"
-#include "content/public/common/notification_resources.h"
-#include "content/public/common/platform_notification_data.h"
 #include "extensions/buildflags/buildflags.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
+#include "third_party/blink/public/common/notifications/notification_resources.h"
+#include "third_party/blink/public/common/notifications/platform_notification_data.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/base/ui_base_features.h"
@@ -126,8 +126,8 @@
     BrowserContext* browser_context,
     const std::string& notification_id,
     const GURL& origin,
-    const content::PlatformNotificationData& notification_data,
-    const content::NotificationResources& notification_resources) {
+    const blink::PlatformNotificationData& notification_data,
+    const blink::NotificationResources& notification_resources) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // Posted tasks can request notifications to be added, which would cause a
@@ -154,8 +154,8 @@
     const std::string& notification_id,
     const GURL& service_worker_scope,
     const GURL& origin,
-    const content::PlatformNotificationData& notification_data,
-    const content::NotificationResources& notification_resources) {
+    const blink::PlatformNotificationData& notification_data,
+    const blink::NotificationResources& notification_resources) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // Posted tasks can request notifications to be added, which would cause a
@@ -328,8 +328,8 @@
     Profile* profile,
     const GURL& origin,
     const std::string& notification_id,
-    const content::PlatformNotificationData& notification_data,
-    const content::NotificationResources& notification_resources) const {
+    const blink::PlatformNotificationData& notification_data,
+    const blink::NotificationResources& notification_resources) const {
   DCHECK_EQ(notification_data.actions.size(),
             notification_resources.action_icons.size());
 
@@ -379,14 +379,14 @@
   // Developer supplied action buttons.
   std::vector<message_center::ButtonInfo> buttons;
   for (size_t i = 0; i < notification_data.actions.size(); ++i) {
-    const content::PlatformNotificationAction& action =
+    const blink::PlatformNotificationAction& action =
         notification_data.actions[i];
     message_center::ButtonInfo button(action.title);
     // TODO(peter): Handle different screen densities instead of always using
     // the 1x bitmap - crbug.com/585815.
     button.icon =
         gfx::Image::CreateFrom1xBitmap(notification_resources.action_icons[i]);
-    if (action.type == content::PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT) {
+    if (action.type == blink::PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT) {
       button.placeholder = action.placeholder.as_optional_string16().value_or(
           l10n_util::GetStringUTF16(IDS_NOTIFICATION_REPLY_PLACEHOLDER));
     }
diff --git a/chrome/browser/notifications/platform_notification_service_impl.h b/chrome/browser/notifications/platform_notification_service_impl.h
index ab8ed4e0..cc1e4db 100644
--- a/chrome/browser/notifications/platform_notification_service_impl.h
+++ b/chrome/browser/notifications/platform_notification_service_impl.h
@@ -52,15 +52,15 @@
       content::BrowserContext* browser_context,
       const std::string& notification_id,
       const GURL& origin,
-      const content::PlatformNotificationData& notification_data,
-      const content::NotificationResources& notification_resources) override;
+      const blink::PlatformNotificationData& notification_data,
+      const blink::NotificationResources& notification_resources) override;
   void DisplayPersistentNotification(
       content::BrowserContext* browser_context,
       const std::string& notification_id,
       const GURL& service_worker_scope,
       const GURL& origin,
-      const content::PlatformNotificationData& notification_data,
-      const content::NotificationResources& notification_resources) override;
+      const blink::PlatformNotificationData& notification_data,
+      const blink::NotificationResources& notification_resources) override;
   void CloseNotification(content::BrowserContext* browser_context,
                          const std::string& notification_id) override;
   void ClosePersistentNotification(content::BrowserContext* browser_context,
@@ -106,8 +106,8 @@
       Profile* profile,
       const GURL& origin,
       const std::string& notification_id,
-      const content::PlatformNotificationData& notification_data,
-      const content::NotificationResources& notification_resources) const;
+      const blink::PlatformNotificationData& notification_data,
+      const blink::NotificationResources& notification_resources) const;
 
   // Returns a display name for an origin, to be used in the context message
   base::string16 DisplayNameForContextMessage(Profile* profile,
diff --git a/chrome/browser/notifications/platform_notification_service_unittest.cc b/chrome/browser/notifications/platform_notification_service_unittest.cc
index 694362d..58cdf9cb 100644
--- a/chrome/browser/notifications/platform_notification_service_unittest.cc
+++ b/chrome/browser/notifications/platform_notification_service_unittest.cc
@@ -26,13 +26,13 @@
 #include "components/history/core/browser/history_service.h"
 #include "components/history/core/test/test_history_database.h"
 #include "components/ukm/test_ukm_recorder.h"
-#include "content/public/common/notification_resources.h"
-#include "content/public/common/platform_notification_data.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "extensions/buildflags/buildflags.h"
 #include "services/metrics/public/cpp/ukm_builders.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/notifications/notification_resources.h"
+#include "third_party/blink/public/common/notifications/platform_notification_data.h"
 
 #if BUILDFLAG(ENABLE_EXTENSIONS)
 #include "chrome/browser/extensions/extension_service.h"
@@ -43,8 +43,8 @@
 #include "extensions/common/value_builder.h"
 #endif  // BUILDFLAG(ENABLE_EXTENSIONS)
 
-using content::NotificationResources;
-using content::PlatformNotificationData;
+using blink::NotificationResources;
+using blink::PlatformNotificationData;
 using content::NotificationDatabaseData;
 using message_center::Notification;
 
@@ -206,9 +206,9 @@
   data.vibration_pattern = vibration_pattern;
   data.silent = true;
   data.actions.resize(2);
-  data.actions[0].type = content::PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON;
+  data.actions[0].type = blink::PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON;
   data.actions[0].title = base::ASCIIToUTF16("Button 1");
-  data.actions[1].type = content::PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT;
+  data.actions[1].type = blink::PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT;
   data.actions[1].title = base::ASCIIToUTF16("Button 2");
 
   NotificationResources notification_resources;
@@ -318,7 +318,7 @@
   data.notification_data.renotify = false;
   data.notification_data.tag = "tag";
   data.notification_data.silent = true;
-  content::PlatformNotificationAction action1, action2, action3;
+  blink::PlatformNotificationAction action1, action2, action3;
   data.notification_data.actions.push_back(action1);
   data.notification_data.actions.push_back(action2);
   data.notification_data.actions.push_back(action3);
diff --git a/chrome/browser/notifications/win/notification_metrics.h b/chrome/browser/notifications/win/notification_metrics.h
index abf2f85..d7f0cf5 100644
--- a/chrome/browser/notifications/win/notification_metrics.h
+++ b/chrome/browser/notifications/win/notification_metrics.h
@@ -88,6 +88,8 @@
   GET_NODE_VALUE_FAILED = 8,
   CONVERSION_TO_PROP_VALUE_FAILED = 9,
   GET_STRING_FAILED = 10,
+  GET_NAMED_ITEM_NULL = 11,
+  GET_FIRST_CHILD_NULL = 12,
   COUNT  // Must be the final value.
 };
 
diff --git a/chrome/browser/notifications/win/notification_util.cc b/chrome/browser/notifications/win/notification_util.cc
index 04f3c9a..c0d5a2a 100644
--- a/chrome/browser/notifications/win/notification_util.cc
+++ b/chrome/browser/notifications/win/notification_util.cc
@@ -77,6 +77,13 @@
     return NotificationLaunchId();
   }
 
+  if (!leaf) {
+    LogGetNotificationLaunchIdStatus(
+        GetNotificationLaunchIdStatus::GET_NAMED_ITEM_NULL);
+    DLOG(ERROR) << "GetNamedItem returned null querying for 'launch' attribute";
+    return NotificationLaunchId();
+  }
+
   mswr::ComPtr<winxml::Dom::IXmlNode> child;
   hr = leaf->get_FirstChild(&child);
   if (FAILED(hr)) {
@@ -86,6 +93,13 @@
     return NotificationLaunchId();
   }
 
+  if (!child) {
+    LogGetNotificationLaunchIdStatus(
+        GetNotificationLaunchIdStatus::GET_FIRST_CHILD_NULL);
+    DLOG(ERROR) << "Launch attribute is a null node";
+    return NotificationLaunchId();
+  }
+
   mswr::ComPtr<IInspectable> inspectable;
   hr = child->get_NodeValue(&inspectable);
   if (FAILED(hr)) {
diff --git a/chrome/browser/password_manager/password_accessory_controller_unittest.cc b/chrome/browser/password_manager/password_accessory_controller_unittest.cc
index df23aec..b675188 100644
--- a/chrome/browser/password_manager/password_accessory_controller_unittest.cc
+++ b/chrome/browser/password_manager/password_accessory_controller_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/optional.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/metrics/histogram_tester.h"
 #include "base/test/mock_callback.h"
 #include "base/test/scoped_task_environment.h"
 #include "chrome/browser/password_manager/password_accessory_view_interface.h"
@@ -24,7 +25,6 @@
 #include "components/autofill/core/common/signatures_util.h"
 #include "components/favicon/core/test/mock_favicon_service.h"
 #include "components/password_manager/core/browser/password_generation_manager.h"
-#include "components/password_manager/core/browser/stub_password_manager_client.h"
 #include "components/password_manager/core/browser/stub_password_manager_driver.h"
 #include "components/strings/grit/components_strings.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -36,6 +36,7 @@
 using autofill::FillingStatus;
 using autofill::PasswordForm;
 using autofill::password_generation::PasswordGenerationUIData;
+using autofill::password_generation::PasswordGenerationUserEvent;
 using base::ASCIIToUTF16;
 using base::UTF16ToWide;
 using testing::_;
@@ -43,6 +44,7 @@
 using testing::ByMove;
 using testing::ElementsAre;
 using testing::Mock;
+using testing::NiceMock;
 using testing::NotNull;
 using testing::PrintToString;
 using testing::Return;
@@ -260,6 +262,15 @@
     NavigateAndCommit(GURL(kExampleSite));
     EXPECT_CALL(*view(), CloseAccessorySheet()).Times(AnyNumber());
     EXPECT_CALL(*view(), SwapSheetWithKeyboard()).Times(AnyNumber());
+
+    // Mock objects needed by password generation
+    mock_password_manager_driver_ =
+        std::make_unique<NiceMock<MockPasswordManagerDriver>>();
+    mock_generation_manager_ =
+        std::make_unique<NiceMock<MockPasswordGenerationManager>>(
+            nullptr, mock_password_manager_driver_.get());
+    mock_dialog_ =
+        std::make_unique<NiceMock<MockPasswordGenerationDialogView>>();
   }
 
   PasswordAccessoryController* controller() {
@@ -279,13 +290,44 @@
     return mock_favicon_service_.get();
   }
 
+ protected:
+  // Sets up mocks needed by the generation flow and signals the
+  // |PasswordAccessoryController| that generation is available.
+  void InitializeGeneration(const base::string16& password);
+
+  std::unique_ptr<NiceMock<MockPasswordManagerDriver>>
+      mock_password_manager_driver_;
+  std::unique_ptr<NiceMock<MockPasswordGenerationManager>>
+      mock_generation_manager_;
+  std::unique_ptr<NiceMock<MockPasswordGenerationDialogView>> mock_dialog_;
+  base::HistogramTester histogram_tester_;
+
  private:
-  base::MockCallback<PasswordAccessoryController::CreateDialogFactory>
+  NiceMock<base::MockCallback<PasswordAccessoryController::CreateDialogFactory>>
       mock_dialog_factory_;
   std::unique_ptr<testing::StrictMock<favicon::MockFaviconService>>
       mock_favicon_service_;
 };
 
+void PasswordAccessoryControllerTest::InitializeGeneration(
+    const base::string16& password) {
+  ON_CALL(*(mock_password_manager_driver_.get()),
+          GetPasswordGenerationManager())
+      .WillByDefault(Return(mock_generation_manager_.get()));
+
+  EXPECT_CALL(*view(), OnAutomaticGenerationStatusChanged(true));
+
+  controller()->OnAutomaticGenerationStatusChanged(
+      true, GetTestGenerationUIData1(),
+      mock_password_manager_driver_->AsWeakPtr());
+
+  ON_CALL(*(mock_generation_manager_.get()), GeneratePassword(_, _, _, _, _))
+      .WillByDefault(Return(password));
+
+  ON_CALL(mock_dialog_factory(), Run)
+      .WillByDefault(Return(ByMove(std::move(mock_dialog_))));
+}
+
 TEST_F(PasswordAccessoryControllerTest, IsNotRecreatedForSameWebContents) {
   PasswordAccessoryController* initial_controller =
       PasswordAccessoryController::FromWebContents(web_contents());
@@ -446,18 +488,14 @@
 // are updated.
 TEST_F(PasswordAccessoryControllerTest,
        UpdatesSignaturesForDifferentGenerationForms) {
-  MockPasswordManagerDriver mock_driver;
-  password_manager::StubPasswordManagerClient stub_client;
-  MockPasswordGenerationManager mock_generation_manager(&stub_client,
-                                                        &mock_driver);
-
   // Called twice for different forms.
   EXPECT_CALL(*view(), OnAutomaticGenerationStatusChanged(true)).Times(2);
   controller()->OnAutomaticGenerationStatusChanged(
-      true, GetTestGenerationUIData1(), (&mock_driver)->AsWeakPtr());
+      true, GetTestGenerationUIData1(),
+      mock_password_manager_driver_->AsWeakPtr());
   PasswordGenerationUIData new_ui_data = GetTestGenerationUIData2();
-  controller()->OnAutomaticGenerationStatusChanged(true, new_ui_data,
-                                                   (&mock_driver)->AsWeakPtr());
+  controller()->OnAutomaticGenerationStatusChanged(
+      true, new_ui_data, mock_password_manager_driver_->AsWeakPtr());
 
   autofill::FormSignature form_signature =
       autofill::CalculateFormSignature(new_ui_data.password_form.form_data);
@@ -465,16 +503,15 @@
       autofill::CalculateFieldSignatureByNameAndType(
           new_ui_data.generation_element, "password");
 
-  std::unique_ptr<MockPasswordGenerationDialogView> dialog_view =
-      std::make_unique<MockPasswordGenerationDialogView>();
-  MockPasswordGenerationDialogView* raw_dialog_view = dialog_view.get();
+  MockPasswordGenerationDialogView* raw_dialog_view = mock_dialog_.get();
 
   base::string16 generated_password = ASCIIToUTF16("t3stp@ssw0rd");
   EXPECT_CALL(mock_dialog_factory(), Run)
-      .WillOnce(Return(ByMove(std::move(dialog_view))));
-  EXPECT_CALL(mock_driver, GetPasswordGenerationManager())
-      .WillOnce(Return(&mock_generation_manager));
-  EXPECT_CALL(mock_generation_manager,
+      .WillOnce(Return(ByMove(std::move(mock_dialog_))));
+  EXPECT_CALL(*(mock_password_manager_driver_.get()),
+              GetPasswordGenerationManager())
+      .WillOnce(Return(mock_generation_manager_.get()));
+  EXPECT_CALL(*(mock_generation_manager_.get()),
               GeneratePassword(_, form_signature, field_signature,
                                uint32_t(new_ui_data.max_length), _))
       .WillOnce(Return(generated_password));
@@ -721,3 +758,74 @@
 
   base::RunLoop().RunUntilIdle();
 }
+
+TEST_F(PasswordAccessoryControllerTest, RecordsGeneratedPasswordAccepted) {
+  base::string16 test_password = ASCIIToUTF16("t3stp@ssw0rd");
+
+  InitializeGeneration(test_password);
+
+  controller()->OnGenerationRequested();
+  controller()->GeneratedPasswordAccepted(test_password);
+
+  histogram_tester_.ExpectUniqueSample(
+      "PasswordGeneration.UserEvent",
+      PasswordGenerationUserEvent::kPasswordAccepted, 1);
+}
+
+TEST_F(PasswordAccessoryControllerTest, RecordsGeneratedPasswordEdited) {
+  base::string16 test_password = ASCIIToUTF16("t3stp@ssw0rd");
+
+  InitializeGeneration(test_password);
+
+  controller()->OnGenerationRequested();
+  controller()->GeneratedPasswordAccepted(test_password);
+  controller()->MaybeGeneratedPasswordChanged(test_password);
+
+  // Since MaybeGeneratedPasswordChanged was called with the same password
+  // the histogram should not record an edit operation.
+  histogram_tester_.ExpectBucketCount(
+      "PasswordGeneration.UserEvent",
+      PasswordGenerationUserEvent::kPasswordEdited, 0);
+
+  controller()->MaybeGeneratedPasswordChanged(
+      ASCIIToUTF16("changed_t3stp@ssw0rd"));
+  histogram_tester_.ExpectBucketCount(
+      "PasswordGeneration.UserEvent",
+      PasswordGenerationUserEvent::kPasswordEdited, 1);
+
+  // Since the edit operation should only be logged once per lifetime
+  // of the generated password, check that changing the password again doesn't
+  // record editing again.
+  controller()->MaybeGeneratedPasswordChanged(
+      ASCIIToUTF16("changed_t3stp@ssw0rd_again"));
+  histogram_tester_.ExpectBucketCount(
+      "PasswordGeneration.UserEvent",
+      PasswordGenerationUserEvent::kPasswordEdited, 1);
+}
+
+TEST_F(PasswordAccessoryControllerTest, RecordsGeneratedPasswordDeleted) {
+  base::string16 test_password = ASCIIToUTF16("t3stp@ssw0rd");
+
+  InitializeGeneration(test_password);
+
+  controller()->OnGenerationRequested();
+  controller()->GeneratedPasswordAccepted(test_password);
+  controller()->GeneratedPasswordDeleted();
+
+  histogram_tester_.ExpectBucketCount(
+      "PasswordGeneration.UserEvent",
+      PasswordGenerationUserEvent::kPasswordDeleted, 1);
+}
+
+TEST_F(PasswordAccessoryControllerTest, RecordsGeneratedPasswordRejected) {
+  base::string16 test_password = ASCIIToUTF16("t3stp@ssw0rd");
+
+  InitializeGeneration(test_password);
+
+  controller()->OnGenerationRequested();
+  controller()->GeneratedPasswordRejected();
+
+  histogram_tester_.ExpectBucketCount(
+      "PasswordGeneration.UserEvent",
+      PasswordGenerationUserEvent::kPasswordRejectedInDialog, 1);
+}
diff --git a/chrome/browser/policy/policy_browsertest.cc b/chrome/browser/policy/policy_browsertest.cc
index b529de2..532628a 100644
--- a/chrome/browser/policy/policy_browsertest.cc
+++ b/chrome/browser/policy/policy_browsertest.cc
@@ -4832,9 +4832,6 @@
                        PasswordProtectionWarningTriggerNotLoggedIn) {
   MockPasswordProtectionService mock_service(
       g_browser_process->safe_browsing_service(), browser()->profile());
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      safe_browsing::kEnterprisePasswordProtectionV1);
 
   // If user is not signed-in, |GetPasswordProtectionWarningTriggerPref(...)|
   // should return |PASSWORD_PROTECTION_OFF| unless specified by policy.
@@ -4871,9 +4868,6 @@
 IN_PROC_BROWSER_TEST_F(PolicyTest, PasswordProtectionWarningTriggerGmail) {
   MockPasswordProtectionService mock_service(
       g_browser_process->safe_browsing_service(), browser()->profile());
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      safe_browsing::kEnterprisePasswordProtectionV1);
 
   // If user is a Gmail user, |GetPasswordProtectionWarningTriggerPref(...)|
   // should return |PHISHING_REUSE| unless specified by policy.
@@ -4912,9 +4906,6 @@
   EXPECT_CALL(mock_service, GetSyncAccountType())
       .WillRepeatedly(Return(safe_browsing::LoginReputationClientRequest::
                                  PasswordReuseEvent::GSUITE));
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      safe_browsing::kEnterprisePasswordProtectionV1);
   const PrefService* const prefs = browser()->profile()->GetPrefs();
   PolicyMap policies;
 
@@ -4945,9 +4936,6 @@
 // Test that when safe browsing whitelist domains are set by policy, safe
 // browsing service gets the correct value.
 IN_PROC_BROWSER_TEST_F(PolicyTest, SafeBrowsingWhitelistDomains) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      safe_browsing::kEnterprisePasswordProtectionV1);
   // Without setting up the enterprise policy,
   // |GetSafeBrowsingDomainsPref(..) should return empty list.
   const PrefService* const prefs = browser()->profile()->GetPrefs();
@@ -4993,9 +4981,6 @@
 // Test that when password protection login URLs are set by policy, password
 // protection service gets the correct value.
 IN_PROC_BROWSER_TEST_F(PolicyTest, PasswordProtectionLoginURLs) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      safe_browsing::kEnterprisePasswordProtectionV1);
   // Without setting up the enterprise policy,
   // |GetPasswordProtectionLoginURLsPref(..) should return empty list.
   const PrefService* const prefs = browser()->profile()->GetPrefs();
@@ -5039,9 +5024,6 @@
 // Test that when password protection change password URL is set by policy,
 // password protection service gets the correct value.
 IN_PROC_BROWSER_TEST_F(PolicyTest, PasswordProtectionChangePasswordURL) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      safe_browsing::kEnterprisePasswordProtectionV1);
   // Without setting up the enterprise policy,
   // |GetEnterpriseChangePasswordURL(..) should return default GAIA change
   // password URL.
diff --git a/chrome/browser/printing/printer_manager_dialog_linux.cc b/chrome/browser/printing/printer_manager_dialog_linux.cc
index 75afe6e..4f56120 100644
--- a/chrome/browser/printing/printer_manager_dialog_linux.cc
+++ b/chrome/browser/printing/printer_manager_dialog_linux.cc
@@ -13,7 +13,7 @@
 #include "base/process/kill.h"
 #include "base/process/launch.h"
 #include "base/task/post_task.h"
-#include "base/threading/thread_restrictions.h"
+#include "base/threading/scoped_blocking_call.h"
 
 namespace {
 
@@ -53,7 +53,7 @@
 // Detect the command based on the deskop environment and open the printer
 // manager dialog.
 void DetectAndOpenPrinterConfigDialog() {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   std::unique_ptr<base::Environment> env(base::Environment::Create());
 
   bool opened = false;
diff --git a/chrome/browser/profile_resetter/profile_resetter.cc b/chrome/browser/profile_resetter/profile_resetter.cc
index 27d2988..88870d8 100644
--- a/chrome/browser/profile_resetter/profile_resetter.cc
+++ b/chrome/browser/profile_resetter/profile_resetter.cc
@@ -26,7 +26,6 @@
 #include "chrome/browser/ui/browser_list.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/pref_names.h"
-#include "chrome/installer/util/browser_distribution.h"
 #include "components/content_settings/core/browser/content_settings_info.h"
 #include "components/content_settings/core/browser/content_settings_registry.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
@@ -57,14 +56,12 @@
   base::FilePath chrome_exe;
   if (!base::PathService::Get(base::FILE_EXE, &chrome_exe))
     return;
-  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
 
   base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   for (int location = ShellUtil::SHORTCUT_LOCATION_FIRST;
        location < ShellUtil::NUM_SHORTCUT_LOCATIONS; ++location) {
     ShellUtil::ShortcutListMaybeRemoveUnknownArgs(
         static_cast<ShellUtil::ShortcutLocation>(location),
-        dist,
         ShellUtil::CURRENT_USER,
         chrome_exe,
         true,
@@ -358,7 +355,6 @@
   base::FilePath chrome_exe;
   if (!base::PathService::Get(base::FILE_EXE, &chrome_exe))
     return std::vector<ShortcutCommand>();
-  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
   std::vector<ShortcutCommand> shortcuts;
   for (int location = ShellUtil::SHORTCUT_LOCATION_FIRST;
        location < ShellUtil::NUM_SHORTCUT_LOCATIONS; ++location) {
@@ -366,7 +362,6 @@
       break;
     ShellUtil::ShortcutListMaybeRemoveUnknownArgs(
         static_cast<ShellUtil::ShortcutLocation>(location),
-        dist,
         ShellUtil::CURRENT_USER,
         chrome_exe,
         false,
diff --git a/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc b/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc
index c3de7aa..ff85fee 100644
--- a/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc
+++ b/chrome/browser/profiles/profile_shortcut_manager_unittest_win.cc
@@ -21,7 +21,6 @@
 #include "chrome/browser/profiles/profile_shortcut_manager_win.h"
 #include "chrome/browser/shell_integration_win.h"
 #include "chrome/grit/chromium_strings.h"
-#include "chrome/installer/util/browser_distribution.h"
 #include "chrome/installer/util/install_util.h"
 #include "chrome/installer/util/shell_util.h"
 #include "chrome/test/base/testing_browser_process.h"
@@ -111,8 +110,7 @@
   base::FilePath GetDefaultShortcutPathForProfile(
       const base::string16& profile_name) {
     return GetUserShortcutsDirectory().Append(
-        profiles::internal::GetShortcutFilenameForProfile(profile_name,
-                                                          GetDistribution()));
+        profiles::internal::GetShortcutFilenameForProfile(profile_name));
   }
 
   // Returns true if the shortcut for this profile exists.
@@ -205,8 +203,8 @@
         base::CreateCOMSTATaskRunnerWithTraits({base::MayBlock()}).get(),
         location,
         base::Bind(&ShellUtil::CreateOrUpdateShortcut,
-                   ShellUtil::SHORTCUT_LOCATION_DESKTOP, GetDistribution(),
-                   properties, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS),
+                   ShellUtil::SHORTCUT_LOCATION_DESKTOP, properties,
+                   ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS),
         base::Bind([](bool succeeded) { EXPECT_TRUE(succeeded); }));
     thread_bundle_.RunUntilIdle();
   }
@@ -231,12 +229,11 @@
 
   base::FilePath CreateRegularSystemLevelShortcut(
       const base::Location& location) {
-    BrowserDistribution* distribution = GetDistribution();
     ShellUtil::ShortcutProperties properties(ShellUtil::SYSTEM_LEVEL);
     ShellUtil::AddDefaultShortcutProperties(GetExePath(), &properties);
     PostCreateOrUpdateShortcut(location, properties);
     const base::FilePath system_level_shortcut_path =
-        GetSystemShortcutsDirectory().Append(distribution->GetShortcutName() +
+        GetSystemShortcutsDirectory().Append(InstallUtil::GetShortcutName() +
                                              installer::kLnkExt);
     EXPECT_TRUE(base::PathExists(system_level_shortcut_path))
         << location.ToString();
@@ -254,10 +251,6 @@
     thread_bundle_.RunUntilIdle();
   }
 
-  BrowserDistribution* GetDistribution() {
-    return BrowserDistribution::GetDistribution();
-  }
-
   base::FilePath GetExePath() {
     base::FilePath exe_path;
     EXPECT_TRUE(base::PathService::Get(base::FILE_EXE, &exe_path));
@@ -267,7 +260,6 @@
   base::FilePath GetUserShortcutsDirectory() {
     base::FilePath user_shortcuts_directory;
     EXPECT_TRUE(ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
-                                           GetDistribution(),
                                            ShellUtil::CURRENT_USER,
                                            &user_shortcuts_directory));
     return user_shortcuts_directory;
@@ -276,7 +268,6 @@
   base::FilePath GetSystemShortcutsDirectory() {
     base::FilePath system_shortcuts_directory;
     EXPECT_TRUE(ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
-                                           GetDistribution(),
                                            ShellUtil::SYSTEM_LEVEL,
                                            &system_shortcuts_directory));
     return system_shortcuts_directory;
@@ -299,12 +290,10 @@
 
 TEST_F(ProfileShortcutManagerTest, ShortcutFilename) {
   const base::string16 kProfileName = L"Harry";
-  BrowserDistribution* distribution = GetDistribution();
   const base::string16 expected_name = kProfileName + L" - " +
       l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME) + installer::kLnkExt;
   EXPECT_EQ(expected_name,
-            profiles::internal::GetShortcutFilenameForProfile(kProfileName,
-                                                              distribution));
+            profiles::internal::GetShortcutFilenameForProfile(kProfileName));
 }
 
 TEST_F(ProfileShortcutManagerTest, ShortcutLongFilenameIsTrimmed) {
@@ -313,27 +302,23 @@
       L"Harry Harry Harry Harry Harry Harry Harry Harry Harry Harry Harry"
       L"Harry Harry Harry Harry Harry Harry Harry Harry Harry Harry Harry";
   const base::string16 file_name =
-      profiles::internal::GetShortcutFilenameForProfile(kLongProfileName,
-                                                        GetDistribution());
+      profiles::internal::GetShortcutFilenameForProfile(kLongProfileName);
   EXPECT_LT(file_name.size(), kLongProfileName.size());
 }
 
 TEST_F(ProfileShortcutManagerTest, ShortcutFilenameStripsReservedCharacters) {
   const base::string16 kProfileName = L"<Harry/>";
   const base::string16 kSanitizedProfileName = L"Harry";
-  BrowserDistribution* distribution = GetDistribution();
   const base::string16 expected_name = kSanitizedProfileName + L" - " +
       l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME) + installer::kLnkExt;
   EXPECT_EQ(expected_name,
-            profiles::internal::GetShortcutFilenameForProfile(kProfileName,
-                                                              distribution));
+            profiles::internal::GetShortcutFilenameForProfile(kProfileName));
 }
 
 TEST_F(ProfileShortcutManagerTest, UnbadgedShortcutFilename) {
-  BrowserDistribution* distribution = GetDistribution();
-  EXPECT_EQ(distribution->GetShortcutName() + installer::kLnkExt,
-            profiles::internal::GetShortcutFilenameForProfile(base::string16(),
-                                                              distribution));
+  EXPECT_EQ(
+      InstallUtil::GetShortcutName() + installer::kLnkExt,
+      profiles::internal::GetShortcutFilenameForProfile(base::string16()));
 }
 
 TEST_F(ProfileShortcutManagerTest, ShortcutFlags) {
@@ -590,8 +575,8 @@
   // a new one without any command-line flags.
   ASSERT_TRUE(base::DeleteFile(
       GetDefaultShortcutPathForProfile(base::string16()), false));
-  const base::FilePath regular_shortcut_path = CreateRegularShortcutWithName(
-      FROM_HERE, GetDistribution()->GetShortcutName());
+  const base::FilePath regular_shortcut_path =
+      CreateRegularShortcutWithName(FROM_HERE, InstallUtil::GetShortcutName());
 
   // Add another profile and check that the shortcut was replaced with
   // a badged shortcut with the right command line for the profile
@@ -607,8 +592,8 @@
   // two new ones without any command-line flags.
   ASSERT_TRUE(base::DeleteFile(
       GetDefaultShortcutPathForProfile(base::string16()), false));
-  const base::FilePath regular_shortcut_path = CreateRegularShortcutWithName(
-      FROM_HERE, GetDistribution()->GetShortcutName());
+  const base::FilePath regular_shortcut_path =
+      CreateRegularShortcutWithName(FROM_HERE, InstallUtil::GetShortcutName());
   const base::FilePath customized_regular_shortcut_path =
       CreateRegularShortcutWithName(FROM_HERE, L"MyChrome");
 
@@ -885,38 +870,38 @@
   std::set<base::FilePath> excludes;
 
   base::string16 shortcut_filename =
-      profiles::internal::GetUniqueShortcutFilenameForProfile(
-          L"Carrie", excludes, GetDistribution());
+      profiles::internal::GetUniqueShortcutFilenameForProfile(L"Carrie",
+                                                              excludes);
   EXPECT_EQ(
       L"Carrie - " + suffix + installer::kLnkExt, shortcut_filename);
   excludes.insert(GetUserShortcutsDirectory().Append(shortcut_filename));
 
   shortcut_filename = profiles::internal::GetUniqueShortcutFilenameForProfile(
-      L"Carrie", excludes, GetDistribution());
+      L"Carrie", excludes);
   EXPECT_EQ(
       L"Carrie - " + suffix + L" (1)" + installer::kLnkExt, shortcut_filename);
   excludes.insert(GetUserShortcutsDirectory().Append(shortcut_filename));
 
   shortcut_filename = profiles::internal::GetUniqueShortcutFilenameForProfile(
-      L"Carrie", excludes, GetDistribution());
+      L"Carrie", excludes);
   EXPECT_EQ(
       L"Carrie - " + suffix + L" (2)" + installer::kLnkExt, shortcut_filename);
   excludes.insert(GetUserShortcutsDirectory().Append(shortcut_filename));
 
   shortcut_filename = profiles::internal::GetUniqueShortcutFilenameForProfile(
-      L"Steven", excludes, GetDistribution());
+      L"Steven", excludes);
   EXPECT_EQ(
       L"Steven - " + suffix + installer::kLnkExt, shortcut_filename);
   excludes.insert(GetUserShortcutsDirectory().Append(shortcut_filename));
 
   shortcut_filename = profiles::internal::GetUniqueShortcutFilenameForProfile(
-      L"Steven", excludes, GetDistribution());
+      L"Steven", excludes);
   EXPECT_EQ(
       L"Steven - " + suffix + L" (1)" + installer::kLnkExt, shortcut_filename);
   excludes.insert(GetUserShortcutsDirectory().Append(shortcut_filename));
 
   shortcut_filename = profiles::internal::GetUniqueShortcutFilenameForProfile(
-      L"Carrie", excludes, GetDistribution());
+      L"Carrie", excludes);
   EXPECT_EQ(
       L"Carrie - " + suffix + L" (3)" + installer::kLnkExt, shortcut_filename);
   excludes.insert(GetUserShortcutsDirectory().Append(shortcut_filename));
@@ -925,14 +910,13 @@
       GetUserShortcutsDirectory().Append(
           L"Carrie - " + suffix + installer::kLnkExt));
   shortcut_filename = profiles::internal::GetUniqueShortcutFilenameForProfile(
-      L"Carrie", excludes, GetDistribution());
+      L"Carrie", excludes);
   EXPECT_EQ(
       L"Carrie - " + suffix + installer::kLnkExt, shortcut_filename);
 }
 
 TEST_F(ProfileShortcutManagerTest, ShortcutFilenameMatcher) {
-  profiles::internal::ShortcutFilenameMatcher matcher(L"Carrie",
-                                                      GetDistribution());
+  profiles::internal::ShortcutFilenameMatcher matcher(L"Carrie");
   const auto suffix = l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME);
 
   EXPECT_TRUE(matcher.IsCanonical(L"Carrie - " + suffix + L" (2)" +
diff --git a/chrome/browser/profiles/profile_shortcut_manager_win.cc b/chrome/browser/profiles/profile_shortcut_manager_win.cc
index d6c97592..f6981da 100644
--- a/chrome/browser/profiles/profile_shortcut_manager_win.cc
+++ b/chrome/browser/profiles/profile_shortcut_manager_win.cc
@@ -40,7 +40,7 @@
 #include "chrome/common/pref_names.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
 #include "chrome/grit/chromium_strings.h"
-#include "chrome/installer/util/browser_distribution.h"
+#include "chrome/installer/util/install_util.h"
 #include "chrome/installer/util/shell_util.h"
 #include "components/prefs/pref_service.h"
 #include "content/public/browser/browser_thread.h"
@@ -174,7 +174,7 @@
 }
 
 // Creates a desktop shortcut icon file (.ico) on the disk for a given profile,
-// badging the browser distribution icon with the profile avatar.
+// badging the icon with the profile avatar.
 // Returns a path to the shortcut icon file on disk, which is empty if this
 // fails. Use index 0 when assigning the resulting file as the icon. If both
 // given bitmaps are empty, an unbadged icon is created.
@@ -255,17 +255,16 @@
 bool GetDesktopShortcutsDirectories(
     base::FilePath* user_shortcuts_directory,
     base::FilePath* system_shortcuts_directory) {
-  BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
   if (user_shortcuts_directory &&
       !ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
-                                  distribution, ShellUtil::CURRENT_USER,
+                                  ShellUtil::CURRENT_USER,
                                   user_shortcuts_directory)) {
     NOTREACHED();
     return false;
   }
   if (system_shortcuts_directory &&
       !ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
-                                  distribution, ShellUtil::SYSTEM_LEVEL,
+                                  ShellUtil::SYSTEM_LEVEL,
                                   system_shortcuts_directory)) {
     NOTREACHED();
     return false;
@@ -394,19 +393,16 @@
     return;
   }
 
-  BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
-
   // Get a new unique shortcut name.
   const base::string16 new_shortcut_filename =
       profiles::internal::GetUniqueShortcutFilenameForProfile(
-          new_profile_name, *desktop_contents, distribution);
+          new_profile_name, *desktop_contents);
   const base::FilePath new_shortcut_path =
       user_shortcuts_directory.Append(new_shortcut_filename);
 
   if (!profile_shortcuts->empty()) {
     // From all profile_shortcuts choose the one with a known (canonical) name.
-    profiles::internal::ShortcutFilenameMatcher matcher(old_profile_name,
-                                                        distribution);
+    profiles::internal::ShortcutFilenameMatcher matcher(old_profile_name);
     auto it = std::find_if(profile_shortcuts->begin(), profile_shortcuts->end(),
                            [&matcher](const base::FilePath& p) {
                              return matcher.IsCanonical(p.BaseName().value());
@@ -446,8 +442,7 @@
     // properties updated by
     // |CreateOrUpdateDesktopShortcutsAndIconForProfile()|.
     const auto old_shortcut_filename =
-        profiles::internal::GetShortcutFilenameForProfile(old_profile_name,
-                                                          distribution);
+        profiles::internal::GetShortcutFilenameForProfile(old_profile_name);
     const base::FilePath possible_old_system_shortcut =
         system_shortcuts_directory.Append(old_shortcut_filename);
     if (base::PathExists(possible_old_system_shortcut)) {
@@ -528,7 +523,6 @@
   }
 
   ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER);
-  BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
   ShellUtil::AddDefaultShortcutProperties(chrome_exe, &properties);
 
   // Only set the profile-specific properties when |profile_name| is non empty.
@@ -553,7 +547,7 @@
       shortcuts.empty()) {
     const base::string16 shortcut_name =
         profiles::internal::GetUniqueShortcutFilenameForProfile(
-            params.profile_name, desktop_contents, distribution);
+            params.profile_name, desktop_contents);
     shortcuts.insert(base::FilePath(shortcut_name));
     operation = ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL;
   }
@@ -562,7 +556,7 @@
     const base::FilePath shortcut_name = shortcut.BaseName().RemoveExtension();
     properties.set_shortcut_name(shortcut_name.value());
     ShellUtil::CreateOrUpdateShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
-                                      distribution, properties, operation);
+                                      properties, operation);
   }
 }
 
@@ -619,15 +613,13 @@
   const bool had_shortcuts = !shortcuts.empty();
   if (ensure_shortcuts_remain && had_shortcuts &&
       !ChromeDesktopShortcutsExist(chrome_exe)) {
-    BrowserDistribution* distribution = BrowserDistribution::GetDistribution();
 
     ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER);
     ShellUtil::AddDefaultShortcutProperties(chrome_exe, &properties);
     properties.set_shortcut_name(
-        profiles::internal::GetShortcutFilenameForProfile(base::string16(),
-                                                          distribution));
+        profiles::internal::GetShortcutFilenameForProfile(base::string16()));
     ShellUtil::CreateOrUpdateShortcut(
-        ShellUtil::SHORTCUT_LOCATION_DESKTOP, distribution, properties,
+        ShellUtil::SHORTCUT_LOCATION_DESKTOP, properties,
         ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL);
   }
 }
@@ -703,30 +695,27 @@
 }
 
 base::string16 GetShortcutFilenameForProfile(
-    const base::string16& profile_name,
-    BrowserDistribution* distribution) {
+    const base::string16& profile_name) {
   base::string16 shortcut_name;
   if (!profile_name.empty()) {
     shortcut_name.append(SanitizeShortcutProfileNameString(profile_name));
     shortcut_name.append(L" - ");
     shortcut_name.append(l10n_util::GetStringUTF16(IDS_SHORT_PRODUCT_NAME));
   } else {
-    shortcut_name.append(distribution->GetShortcutName());
+    shortcut_name.append(InstallUtil::GetShortcutName());
   }
   return shortcut_name + installer::kLnkExt;
 }
 
 base::string16 GetUniqueShortcutFilenameForProfile(
     const base::string16& profile_name,
-    const std::set<base::FilePath>& excludes,
-    BrowserDistribution* distribution) {
+    const std::set<base::FilePath>& excludes) {
   std::set<base::string16> excludes_names;
   std::transform(excludes.begin(), excludes.end(),
                  std::inserter(excludes_names, excludes_names.begin()),
                  [](const base::FilePath& e) { return e.BaseName().value(); });
 
-  const auto base_name =
-      GetShortcutFilenameForProfile(profile_name, distribution);
+  const auto base_name = GetShortcutFilenameForProfile(profile_name);
   auto name = base_name;
   const base::FilePath base_path(base_name);
   for (int uniquifier = 1; excludes_names.count(name) > 0; ++uniquifier) {
@@ -738,10 +727,8 @@
 
 // Corresponds to GetUniqueShortcutFilenameForProfile.
 ShortcutFilenameMatcher::ShortcutFilenameMatcher(
-    const base::string16& profile_name,
-    BrowserDistribution* distribution)
-    : profile_shortcut_filename_(
-          GetShortcutFilenameForProfile(profile_name, distribution)),
+    const base::string16& profile_name)
+    : profile_shortcut_filename_(GetShortcutFilenameForProfile(profile_name)),
       lnk_ext_(installer::kLnkExt),
       profile_shortcut_name_(profile_shortcut_filename_) {
   DCHECK(profile_shortcut_name_.ends_with(lnk_ext_));
@@ -876,8 +863,7 @@
     shortcut_profile_name = entry->GetName();
 
   *name = base::FilePath(profiles::internal::GetShortcutFilenameForProfile(
-                             shortcut_profile_name,
-                             BrowserDistribution::GetDistribution()))
+                             shortcut_profile_name))
               .RemoveExtension()
               .value();
 
diff --git a/chrome/browser/profiles/profile_shortcut_manager_win.h b/chrome/browser/profiles/profile_shortcut_manager_win.h
index b6c57ec..5678dd4 100644
--- a/chrome/browser/profiles/profile_shortcut_manager_win.h
+++ b/chrome/browser/profiles/profile_shortcut_manager_win.h
@@ -14,8 +14,6 @@
 #include "content/public/browser/notification_observer.h"
 #include "content/public/browser/notification_registrar.h"
 
-class BrowserDistribution;
-
 // Internal free-standing functions that are exported here for testing.
 namespace profiles {
 namespace internal {
@@ -23,24 +21,22 @@
 // Returns the full path to the profile icon file.
 base::FilePath GetProfileIconPath(const base::FilePath& profile_path);
 
-// Returns the default shortcut filename for the given profile name,
-// given |distribution|. Returns a filename appropriate for a
-// single-user installation if |profile_name| is empty.
-base::string16 GetShortcutFilenameForProfile(const base::string16& profile_name,
-                                             BrowserDistribution* distribution);
+// Returns the default shortcut filename for the given profile name. Returns a
+// filename appropriate for a single-user installation if |profile_name| is
+// empty.
+base::string16 GetShortcutFilenameForProfile(
+    const base::string16& profile_name);
 
 // The same as GetShortcutFilenameForProfile but uniqueness is guaranteed.
 // Makes an unique filename among |excludes|.
 base::string16 GetUniqueShortcutFilenameForProfile(
     const base::string16& profile_name,
-    const std::set<base::FilePath>& excludes,
-    BrowserDistribution* distribution);
+    const std::set<base::FilePath>& excludes);
 
 // This class checks that shortcut filename matches certain profile.
 class ShortcutFilenameMatcher {
  public:
-  ShortcutFilenameMatcher(const base::string16& profile_name,
-                          BrowserDistribution* distribution);
+  explicit ShortcutFilenameMatcher(const base::string16& profile_name);
 
   // Check that shortcut filename has a name given by us (by
   // GetShortcutFilenameForProfile or GetUniqueShortcutFilenameForProfile).
diff --git a/chrome/browser/push_messaging/push_messaging_notification_manager.cc b/chrome/browser/push_messaging/push_messaging_notification_manager.cc
index 9eec43f7..2319791 100644
--- a/chrome/browser/push_messaging/push_messaging_notification_manager.cc
+++ b/chrome/browser/push_messaging/push_messaging_notification_manager.cc
@@ -28,10 +28,10 @@
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/browser/web_contents.h"
-#include "content/public/common/notification_resources.h"
 #include "content/public/common/push_messaging_status.mojom.h"
 #include "content/public/common/url_constants.h"
 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
+#include "third_party/blink/public/common/notifications/notification_resources.h"
 #include "third_party/blink/public/mojom/page/page_visibility_state.mojom.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "url/gurl.h"
@@ -47,9 +47,7 @@
 
 using content::BrowserThread;
 using content::NotificationDatabaseData;
-using content::NotificationResources;
 using content::PlatformNotificationContext;
-using content::PlatformNotificationData;
 using content::PushMessagingService;
 using content::ServiceWorkerContext;
 using content::WebContents;
@@ -67,11 +65,11 @@
 NotificationDatabaseData CreateDatabaseData(
     const GURL& origin,
     int64_t service_worker_registration_id) {
-  PlatformNotificationData notification_data;
+  blink::PlatformNotificationData notification_data;
   notification_data.title = url_formatter::FormatUrlForSecurityDisplay(
       origin, url_formatter::SchemeDisplay::OMIT_HTTP_AND_HTTPS);
   notification_data.direction =
-      PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT;
+      blink::PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT;
   notification_data.body =
       l10n_util::GetStringUTF16(IDS_PUSH_MESSAGING_GENERIC_NOTIFICATION_BODY);
   notification_data.tag = kPushMessagingForcedNotificationTag;
@@ -285,7 +283,7 @@
 void PushMessagingNotificationManager::DidWriteNotificationDataIOProxy(
     const base::WeakPtr<PushMessagingNotificationManager>& ui_weak_ptr,
     const GURL& origin,
-    const PlatformNotificationData& notification_data,
+    const blink::PlatformNotificationData& notification_data,
     const base::Closure& message_handled_closure,
     bool success,
     const std::string& notification_id) {
@@ -300,7 +298,7 @@
 
 void PushMessagingNotificationManager::DidWriteNotificationData(
     const GURL& origin,
-    const PlatformNotificationData& notification_data,
+    const blink::PlatformNotificationData& notification_data,
     const base::Closure& message_handled_closure,
     bool success,
     const std::string& notification_id) {
@@ -317,7 +315,7 @@
   // rarely.
   PlatformNotificationServiceImpl::GetInstance()->DisplayPersistentNotification(
       profile_, notification_id, GURL() /* service_worker_scope */, origin,
-      notification_data, NotificationResources());
+      notification_data, blink::NotificationResources());
 
   message_handled_closure.Run();
 }
diff --git a/chrome/browser/push_messaging/push_messaging_notification_manager.h b/chrome/browser/push_messaging/push_messaging_notification_manager.h
index dfe67f6..f682d90 100644
--- a/chrome/browser/push_messaging/push_messaging_notification_manager.h
+++ b/chrome/browser/push_messaging/push_messaging_notification_manager.h
@@ -19,10 +19,13 @@
 
 namespace content {
 struct NotificationDatabaseData;
-struct PlatformNotificationData;
 class WebContents;
 }
 
+namespace blink {
+struct PlatformNotificationData;
+}
+
 // Developers may be required to display a Web Notification in response to an
 // incoming push message in order to clarify to the user that something has
 // happened in the background. When they forget to do so, a default notification
@@ -82,14 +85,14 @@
   static void DidWriteNotificationDataIOProxy(
       const base::WeakPtr<PushMessagingNotificationManager>& ui_weak_ptr,
       const GURL& origin,
-      const content::PlatformNotificationData& notification_data,
+      const blink::PlatformNotificationData& notification_data,
       const base::Closure& message_handled_closure,
       bool success,
       const std::string& notification_id);
 
   void DidWriteNotificationData(
       const GURL& origin,
-      const content::PlatformNotificationData& notification_data,
+      const blink::PlatformNotificationData& notification_data,
       const base::Closure& message_handled_closure,
       bool success,
       const std::string& notification_id);
diff --git a/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html b/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html
index e9e35f21..71f7680 100644
--- a/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html
+++ b/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html
@@ -49,7 +49,7 @@
     <iron-collapse opened="[[prefs.settings.accessibility.value]]">
       <div class="settings-box"
           on-click="onChromeVoxSettingsTap_" actionable>
-        <div class="start">$i18n{chromeVoxOptionsLabel}</div>
+        <div class="start" aria-hidden="true">$i18n{chromeVoxOptionsLabel}</div>
         <paper-icon-button-light class="icon-external">
           <button aria-label="$i18n{chromeVoxOptionsLabel}"></button>
         </paper-icon-button-light>
@@ -67,7 +67,9 @@
     <iron-collapse opened="[[prefs.settings.a11y.select_to_speak.value]]">
       <div class="settings-box"
           on-click="onSelectToSpeakSettingsTap_" actionable>
-        <div class="start">$i18n{selectToSpeakOptionsLabel}</div>
+        <div class="start" aria-hidden="true">
+          $i18n{selectToSpeakOptionsLabel}
+        </div>
         <paper-icon-button-light class="icon-external">
           <button aria-label="$i18n{selectToSpeakOptionsLabel}"></button>
         </paper-icon-button-light>
@@ -75,7 +77,7 @@
     </iron-collapse>
     <div class="settings-box two-line" on-click="onManageTtsSettingsTap_"
         actionable>
-      <div class="start">
+      <div class="start" aria-hidden="true">
         $i18n{manageTtsSettings}
         <div class="secondary" id="appearanceSettingsSecondary">
           $i18n{ttsSettingsLinkDescription}
@@ -121,7 +123,7 @@
       </div>
     </template>
     <div class="settings-box two-line" on-click="onDisplayTap_" actionable>
-      <div class="start">
+      <div class="start" aria-hidden="true">
         $i18n{displaySettingsTitle}
         <div class="secondary" id="displaySettingsSecondary">
           $i18n{displaySettingsDescription}
@@ -133,7 +135,7 @@
       </paper-icon-button-light>
     </div>
     <div class="settings-box two-line" on-click="onAppearanceTap_" actionable>
-      <div class="start">
+      <div class="start" aria-hidden="true">
         $i18n{appearanceSettingsTitle}
         <div class="secondary" id="appearanceSettingsSecondary">
           $i18n{appearanceSettingsDescription}
@@ -175,7 +177,9 @@
       <iron-collapse opened="[[prefs.settings.a11y.switch_access.value]]">
         <div class="settings-box continuation" actionable
             on-click="onSwitchAccessSettingsTap_">
-          <div class="start">$i18n{switchAccessOptionsLabel}</div>
+          <div class="start" aria-hidden="true">
+            $i18n{switchAccessOptionsLabel}
+          </div>
           <paper-icon-button-light class="icon-external">
             <button aria-label="$i18n{switchAccessOptionsLabel}"></button>
           </paper-icon-button-light>
@@ -183,7 +187,7 @@
       </iron-collapse>
     </template>
     <div class="settings-box two-line" on-click="onKeyboardTap_" actionable>
-      <div class="start">
+      <div class="start" aria-hidden="true">
         $i18n{keyboardSettingsTitle}
         <div class="secondary" id="keyboardSettingsSecondary">
           $i18n{keyboardSettingsDescription}
@@ -227,16 +231,16 @@
         label="$i18n{cursorHighlightLabel}">
     </settings-toggle-button>
     <div class="settings-box two-line" on-click="onMouseTap_" actionable>
-      <div class="start">
+      <div class="start" aria-hidden="true">
         $i18n{mouseSettingsTitle}
         <div class="secondary" id="mouseSettingsSecondary">
           $i18n{mouseSettingsDescription}
         </div>
-        </div>
-        <paper-icon-button-light class="subpage-arrow">
-          <button aria-label="$i18n{mouseSettingsTitle}"
-              aria-describedby="mouseSettingsSecondary"></button>
-        </paper-icon-button-light>
+      </div>
+      <paper-icon-button-light class="subpage-arrow">
+        <button aria-label="$i18n{mouseSettingsTitle}"
+            aria-describedby="mouseSettingsSecondary"></button>
+      </paper-icon-button-light>
     </div>
 
     <h2>$i18n{audioHeading}</h2>
diff --git a/chrome/browser/resources/settings/controls/settings_toggle_button.html b/chrome/browser/resources/settings/controls/settings_toggle_button.html
index dcf5114..60612bf0 100644
--- a/chrome/browser/resources/settings/controls/settings_toggle_button.html
+++ b/chrome/browser/resources/settings/controls/settings_toggle_button.html
@@ -55,8 +55,8 @@
     </style>
     <div id="outerRow" noSubLabel$="[[!subLabel]]">
       <div class="flex" id="labelWrapper" hidden$="[[!label]]">
-        <div id="label" class="label">[[label]]</div>
-        <div id="subLabel" class="secondary label">[[subLabel]]</div>
+        <div class="label"  aria-hidden="true">[[label]]</div>
+        <div class="secondary label">[[subLabel]]</div>
       </div>
       <slot name="more-actions"></slot>
       <template is="dom-if" if="[[hasPrefPolicyIndicator(pref.*)]]">
@@ -66,7 +66,6 @@
       <cr-toggle id="control" checked="{{checked}}"
           on-change="onChange_"
           aria-label$="[[getAriaLabel_(label, ariaLabel)]]"
-          aria-describedby="subLabel"
           disabled="[[controlDisabled(disabled, pref)]]">
       </cr-toggle>
     </div>
diff --git a/chrome/browser/resources/settings/people_page/sync_page.html b/chrome/browser/resources/settings/people_page/sync_page.html
index 4165896..6007ce8f 100644
--- a/chrome/browser/resources/settings/people_page/sync_page.html
+++ b/chrome/browser/resources/settings/people_page/sync_page.html
@@ -31,9 +31,7 @@
         opacity: var(--cr-disabled-opacity);
       }
 
-      #create-password-box,
-      #reset-sync-message-box-encryption,
-      #reset-sync-message-box-user-events {
+      #create-password-box {
         /* In order to line up with the encryption radio box text. */
         margin-inline-start: var(--settings-indent-width);
       }
@@ -73,6 +71,10 @@
         border-top: var(--settings-separator-line);
       }
 
+      .passphrase-reset-icon {
+        margin-right: 8px;
+      }
+
 <if expr="not chromeos">
       #toast {
         color: white;
@@ -361,19 +363,20 @@
           <!-- User events is disabled and unchecked if data is encrypted or
                typed urls are disabled. -->
           <template is="dom-if" if="[[unifiedConsentEnabled]]">
-            <div class="layout horizontal list-item"
-                hidden="[[!syncPrefs.userEventsRegistered]]">
+            <div hidden="[[!syncPrefs.userEventsRegistered]]"
+                class$="[[getPassphraseHintLines_(syncPrefs.encryptAllData)]]
+                    layout horizontal list-item">
               <div class="start" id="userEventsCheckboxLabel">
-                <div>$i18n{userEventsCheckboxLabel}</div>
+                $i18n{userEventsCheckboxLabel}
                 <div class="secondary">
                   $i18n{userEventsCheckboxText}
-                </div>
-                <div id="reset-sync-message-box-user-events" class="list-item"
-                  hidden="[[!syncPrefs.encryptAllData]]">
-                  <span>
-                    <iron-icon icon="settings:info-outline"></iron-icon>
-                    $i18nRaw{passphraseResetHint}
-                  </span>
+                  <div id="reset-sync-message-box-user-events"
+                      hidden="[[!syncPrefs.encryptAllData]]">
+                    <iron-icon icon="settings:info-outline"
+                        class="passphrase-reset-icon">
+                    </iron-icon>
+                    $i18nRaw{passphraseResetHintToggle}
+                  </div>
                 </div>
               </div>
               <cr-toggle id="userEventsToggle"
@@ -425,10 +428,19 @@
 
           <div id="encryptionDescription"
               hidden="[[syncPrefs.passphraseRequired]]"
-              class$="two-line single-column
+              class$="single-column
+                  [[getPassphraseHintLines_(syncPrefs.encryptAllData)]]
                   [[getListItemClass_(unifiedConsentEnabled)]]">
-            <div>$i18n{encryptionOptionsTitle}</div>
-            <div class="secondary">$i18n{syncDataEncryptedText}</div>
+            $i18n{encryptionOptionsTitle}
+            <div class="secondary">
+              $i18n{syncDataEncryptedText}
+              <div hidden="[[!syncPrefs.encryptAllData]]">
+                <iron-icon icon="settings:info-outline"
+                    class="passphrase-reset-icon">
+                </iron-icon>
+                $i18nRaw{passphraseResetHintEncryption}
+              </div>
+            </div>
           </div>
 
           <div id="encryptionRadioGroupContainer" class="list-frame"
@@ -455,16 +467,6 @@
                 </template>
               </cr-radio-button>
             </paper-radio-group>
-
-            <!-- duplicated from above -->
-            <div id="reset-sync-message-box-encryption" class="list-item"
-                hidden="[[!syncPrefs.encryptAllData]]">
-              <span>
-                <iron-icon icon="settings:info-outline"></iron-icon>
-                $i18nRaw{passphraseResetHint}
-              </span>
-            </div>
-
           </div>
 
           <template is="dom-if" if="[[creatingNewPassphrase_]]">
diff --git a/chrome/browser/resources/settings/people_page/sync_page.js b/chrome/browser/resources/settings/people_page/sync_page.js
index 46b51344..559f2dc 100644
--- a/chrome/browser/resources/settings/people_page/sync_page.js
+++ b/chrome/browser/resources/settings/people_page/sync_page.js
@@ -657,6 +657,16 @@
     return this.unifiedConsentEnabled ? 'list-item' : 'settings-box';
   },
 
+  /**
+   * When there is a sync passphrase, some items have an additional line for the
+   * passphrase reset hint, making them three lines rather than two.
+   * @return {string}
+   * @private
+   */
+  getPassphraseHintLines_: function() {
+    return this.syncPrefs.encryptAllData ? 'three-line' : 'two-line';
+  },
+
   // <if expr="not chromeos">
   /**
    * @return {boolean}
diff --git a/chrome/browser/resources/settings/settings_shared_css.html b/chrome/browser/resources/settings/settings_shared_css.html
index b9dc5f8..f78d3de5 100644
--- a/chrome/browser/resources/settings/settings_shared_css.html
+++ b/chrome/browser/resources/settings/settings_shared_css.html
@@ -196,6 +196,12 @@
         min-height: var(--settings-row-two-line-min-height);
       }
 
+      /* A row with three lines of text. Often the lower lines will be
+       * .secondary. */
+      .three-line {
+        min-height: var(--settings-row-three-line-min-height);
+      }
+
       /* A settings-box is a horizontal row of text or controls within a
        * setting section (page or subpage). */
       .settings-box {
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service.cc b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
index 6ca5c851..f867e3b9 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service.cc
@@ -451,7 +451,6 @@
     ReusedPasswordType password_type) {
   DCHECK(password_type == PasswordReuseEvent::SIGN_IN_PASSWORD ||
          password_type == PasswordReuseEvent::ENTERPRISE_PASSWORD);
-  DCHECK(base::FeatureList::IsEnabled(kEnterprisePasswordProtectionV1));
   // Exit fullscreen if this |web_contents| is showing in fullscreen mode.
   if (web_contents->IsFullscreenForCurrentTab())
     web_contents->ExitFullscreen(/*will_cause_resize=*/true);
@@ -965,15 +964,12 @@
 }
 
 GURL ChromePasswordProtectionService::GetEnterpriseChangePasswordURL() const {
-  if (base::FeatureList::IsEnabled(kEnterprisePasswordProtectionV1)) {
-    // If change password URL is specified in preferences, returns the
-    // corresponding pref value.
-    GURL enterprise_change_password_url =
-        GetPasswordProtectionChangePasswordURLPref(*profile_->GetPrefs());
-    if (!enterprise_change_password_url.is_empty()) {
-      return enterprise_change_password_url;
-    }
-  }
+  // If change password URL is specified in preferences, returns the
+  // corresponding pref value.
+  GURL enterprise_change_password_url =
+      GetPasswordProtectionChangePasswordURLPref(*profile_->GetPrefs());
+  if (!enterprise_change_password_url.is_empty())
+    return enterprise_change_password_url;
 
   return GetDefaultChangePasswordURL();
 }
@@ -1159,10 +1155,8 @@
 PasswordProtectionTrigger
 ChromePasswordProtectionService::GetPasswordProtectionWarningTriggerPref()
     const {
-  bool is_policy_managed =
-      base::FeatureList::IsEnabled(kEnterprisePasswordProtectionV1) &&
-      profile_->GetPrefs()->HasPrefPath(
-          prefs::kPasswordProtectionWarningTrigger);
+  bool is_policy_managed = profile_->GetPrefs()->HasPrefPath(
+      prefs::kPasswordProtectionWarningTrigger);
   PasswordProtectionTrigger trigger_level =
       static_cast<PasswordProtectionTrigger>(profile_->GetPrefs()->GetInteger(
           prefs::kPasswordProtectionWarningTrigger));
@@ -1212,12 +1206,8 @@
   DCHECK(password_type == PasswordReuseEvent::SIGN_IN_PASSWORD ||
          password_type == PasswordReuseEvent::ENTERPRISE_PASSWORD);
   if (password_type == PasswordReuseEvent::ENTERPRISE_PASSWORD) {
-    return base::FeatureList::IsEnabled(
-               safe_browsing::kEnterprisePasswordProtectionV1)
-               ? l10n_util::GetStringUTF16(
-                     IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS_ENTERPRISE)
-               : l10n_util::GetStringUTF16(
-                     IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS);
+    return l10n_util::GetStringUTF16(
+        IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS_ENTERPRISE);
   }
 
   if (GetSyncAccountType() !=
diff --git a/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc b/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc
index 21c4859..f8b8543 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service_browsertest.cc
@@ -6,7 +6,6 @@
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
-#include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/account_fetcher_service_factory.h"
@@ -27,7 +26,6 @@
 #include "components/prefs/pref_service.h"
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/safe_browsing/common/safe_browsing_prefs.h"
-#include "components/safe_browsing/features.h"
 #include "components/safe_browsing/password_protection/password_protection_request.h"
 #include "components/security_state/core/security_state.h"
 #include "components/signin/core/browser/account_info.h"
@@ -130,7 +128,6 @@
   void ConfigureEnterprisePasswordProtection(
       bool is_gsuite,
       PasswordProtectionTrigger trigger_type) {
-    scoped_features_.InitAndEnableFeature(kEnterprisePasswordProtectionV1);
     if (is_gsuite)
       PrepareSyncAccount("example.com", "stub-user@example.com");
     browser()->profile()->GetPrefs()->SetInteger(
@@ -144,7 +141,6 @@
   std::unique_ptr<
       base::CallbackList<void(content::BrowserContext*)>::Subscription>
       will_create_browser_context_services_subscription_;
-  base::test::ScopedFeatureList scoped_features_;
 };
 
 IN_PROC_BROWSER_TEST_F(ChromePasswordProtectionServiceBrowserTest,
@@ -462,14 +458,6 @@
                        VerifyIsPasswordReuseProtectionConfigured) {
   Profile* profile = browser()->profile();
   ChromePasswordProtectionService* service = GetService(/*is_incognito=*/false);
-  // When kEnterprisePasswordProtectionV1 feature is off.
-  // |IsPasswordReuseProtectionConfigured(..)| returns false.
-  EXPECT_FALSE(
-      ChromePasswordProtectionService::IsPasswordReuseProtectionConfigured(
-          profile));
-
-  base::test::ScopedFeatureList scoped_features;
-  scoped_features.InitAndEnableFeature(kEnterprisePasswordProtectionV1);
   // If prefs::kPasswordProtectionWarningTrigger isn't set to PASSWORD_REUSE,
   // |IsPasswordReuseProtectionConfigured(..)| returns false.
   EXPECT_EQ(PASSWORD_PROTECTION_OFF,
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 01d37cf..763bca19 100644
--- a/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/chrome_password_protection_service_unittest.cc
@@ -9,7 +9,6 @@
 #include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/bind_test_util.h"
-#include "base/test/scoped_feature_list.h"
 #include "chrome/browser/extensions/api/safe_browsing_private/safe_browsing_private_event_router_factory.h"
 #include "chrome/browser/safe_browsing/test_extension_event_observer.h"
 #include "chrome/browser/safe_browsing/ui_manager.h"
@@ -34,7 +33,6 @@
 #include "components/prefs/scoped_user_pref_update.h"
 #include "components/safe_browsing/common/utils.h"
 #include "components/safe_browsing/db/v4_protocol_manager_util.h"
-#include "components/safe_browsing/features.h"
 #include "components/safe_browsing/password_protection/password_protection_navigation_throttle.h"
 #include "components/safe_browsing/password_protection/password_protection_request.h"
 #include "components/signin/core/browser/account_tracker_service.h"
@@ -350,9 +348,6 @@
 
   // If password protection pinging is disabled by policy,
   // |IsPingingEnabled(..)| should return false.
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(
-      safe_browsing::kEnterprisePasswordProtectionV1);
   profile()->GetPrefs()->SetInteger(prefs::kPasswordProtectionWarningTrigger,
                                     PASSWORD_PROTECTION_OFF);
   service_->ConfigService(false /*incognito*/, false /*SBER*/);
@@ -369,9 +364,6 @@
 
 TEST_F(ChromePasswordProtectionServiceTest,
        VerifyPingingIsSkippedIfMatchEnterpriseWhitelist) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(
-      safe_browsing::kEnterprisePasswordProtectionV1);
   RequestOutcome reason = RequestOutcome::UNKNOWN;
   ASSERT_FALSE(
       profile()->GetPrefs()->HasPrefPath(prefs::kSafeBrowsingWhitelistDomains));
@@ -764,10 +756,6 @@
 }
 
 TEST_F(ChromePasswordProtectionServiceTest, VerifyGetEnterprisePasswordURL) {
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      safe_browsing::kEnterprisePasswordProtectionV1);
-
   // If enterprise change password url is not set. This will return the default
   // GAIA change password url.
   EXPECT_TRUE(service_->GetEnterpriseChangePasswordURL().DomainIs(
@@ -922,8 +910,6 @@
 TEST_F(ChromePasswordProtectionServiceTest,
        VerifyOnPolicySpecifiedPasswordChangedEvent) {
   TestExtensionEventObserver event_observer(test_event_router_);
-  base::test::ScopedFeatureList scoped_features;
-  scoped_features.InitAndEnableFeature(kEnterprisePasswordProtectionV1);
 
   // Preparing sync account.
   SigninManagerBase* signin_manager =
@@ -954,8 +940,6 @@
 TEST_F(ChromePasswordProtectionServiceTest,
        VerifyOnPolicySpecifiedPasswordReuseDetectedEventForPasswordReuse) {
   TestExtensionEventObserver event_observer(test_event_router_);
-  base::test::ScopedFeatureList scoped_features;
-  scoped_features.InitAndEnableFeature(kEnterprisePasswordProtectionV1);
   SigninManagerBase* signin_manager =
       SigninManagerFactory::GetForProfile(profile());
   signin_manager->SetAuthenticatedAccountInfo(kTestGaiaID, kTestEmail);
@@ -992,8 +976,6 @@
 TEST_F(ChromePasswordProtectionServiceTest,
        VerifyOnPolicySpecifiedPasswordReuseDetectedEventForPhishingReuse) {
   TestExtensionEventObserver event_observer(test_event_router_);
-  base::test::ScopedFeatureList scoped_features;
-  scoped_features.InitAndEnableFeature(kEnterprisePasswordProtectionV1);
   SigninManagerBase* signin_manager =
       SigninManagerFactory::GetForProfile(profile());
   signin_manager->SetAuthenticatedAccountInfo(kTestGaiaID, kTestEmail);
@@ -1032,9 +1014,6 @@
       IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS_ENTERPRISE_WITH_ORG_NAME,
       base::UTF8ToUTF16("example.com"));
 
-  // Enables kEnterprisePasswordProtectionV1 feature.
-  base::test::ScopedFeatureList scoped_features;
-  scoped_features.InitAndEnableFeature(kEnterprisePasswordProtectionV1);
   EXPECT_EQ(default_warning_text, service_->GetWarningDetailText(
                                       PasswordReuseEvent::SIGN_IN_PASSWORD));
   EXPECT_EQ(
@@ -1062,9 +1041,6 @@
   base::string16 generic_enterprise_warning_text = l10n_util::GetStringUTF16(
       IDS_PAGE_INFO_CHANGE_PASSWORD_DETAILS_ENTERPRISE);
 
-  // Enables kEnterprisePasswordProtectionV1 feature.
-  base::test::ScopedFeatureList scoped_features;
-  scoped_features.InitAndEnableFeature(kEnterprisePasswordProtectionV1);
   EXPECT_EQ(default_warning_text, service_->GetWarningDetailText(
                                       PasswordReuseEvent::SIGN_IN_PASSWORD));
   EXPECT_EQ(
diff --git a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
index f37df22..7336c75 100644
--- a/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
+++ b/chrome/browser/safe_browsing/safe_browsing_blocking_page_test.cc
@@ -1653,8 +1653,6 @@
 // enterprise safe browsing whitelist domains.
 IN_PROC_BROWSER_TEST_P(SafeBrowsingBlockingPageBrowserTest,
                        VerifyEnterpriseWhitelist) {
-  base::test::ScopedFeatureList scoped_features;
-  scoped_features.InitAndEnableFeature(kEnterprisePasswordProtectionV1);
   GURL url = embedded_test_server()->GetURL(kEmptyPage);
   // Add test server domain into the enterprise whitelist.
   base::ListValue whitelist;
diff --git a/chrome/browser/shell_integration.h b/chrome/browser/shell_integration.h
index 26720852..a7bd5219 100644
--- a/chrome/browser/shell_integration.h
+++ b/chrome/browser/shell_integration.h
@@ -122,9 +122,6 @@
                        base::CommandLine* command_line);
 
 #if !defined(OS_WIN)
-// TODO(calamity): replace with
-// BrowserDistribution::GetStartMenuShortcutSubfolder() once
-// BrowserDistribution is cross-platform.
 // Gets the name of the Chrome Apps menu folder in which to place app
 // shortcuts. This is needed for Mac and Linux.
 base::string16 GetAppShortcutsSubdirName();
diff --git a/chrome/browser/shell_integration_win.cc b/chrome/browser/shell_integration_win.cc
index 6c3cf5cf..f6d2196 100644
--- a/chrome/browser/shell_integration_win.cc
+++ b/chrome/browser/shell_integration_win.cc
@@ -264,8 +264,7 @@
   }
 
   void OnBrowserChosen(const base::string16& browser_name) override {
-    if (browser_name ==
-        BrowserDistribution::GetDistribution()->GetDisplayName()) {
+    if (browser_name == InstallUtil::GetDisplayName()) {
       base::RecordAction(
           base::UserMetricsAction("SettingsAppMonitor.ChromeBrowserChosen"));
     } else {
diff --git a/chrome/browser/subresource_filter/ad_tagging_browsertest.cc b/chrome/browser/subresource_filter/ad_tagging_browsertest.cc
index 794269f4..80b4829 100644
--- a/chrome/browser/subresource_filter/ad_tagging_browsertest.cc
+++ b/chrome/browser/subresource_filter/ad_tagging_browsertest.cc
@@ -222,7 +222,8 @@
       AdsPageLoadMetricsObserver::AdOriginStatus::kSame, 1);
 }
 
-IN_PROC_BROWSER_TEST_F(AdTaggingBrowserTest, VerifyCrossOriginWithoutNavigate) {
+IN_PROC_BROWSER_TEST_F(AdTaggingBrowserTest,
+                       DISABLED_VerifyCrossOriginWithoutNavigate) {
   base::HistogramTester histogram_tester;
 
   // Main frame.
diff --git a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
index c66db09..2debef4 100644
--- a/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
+++ b/chrome/browser/sync/test/integration/profile_sync_service_harness.cc
@@ -5,14 +5,11 @@
 #include "chrome/browser/sync/test/integration/profile_sync_service_harness.h"
 
 #include <cstddef>
-#include <iterator>
-#include <ostream>
 #include <sstream>
 
 #include "base/json/json_writer.h"
 #include "base/logging.h"
 #include "base/memory/ptr_util.h"
-#include "base/strings/stringprintf.h"
 #include "base/test/bind_test_util.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/signin/identity_manager_factory.h"
@@ -28,16 +25,11 @@
 #include "chrome/browser/ui/webui/signin/login_ui_test_utils.h"
 #include "chrome/browser/unified_consent/unified_consent_service_factory.h"
 #include "chrome/common/channel_info.h"
-#include "chrome/common/chrome_switches.h"
-#include "components/invalidation/impl/p2p_invalidation_service.h"
 #include "components/signin/core/browser/signin_manager.h"
-#include "components/signin/core/browser/signin_metrics.h"
-#include "components/sync/base/progress_marker_map.h"
 #include "components/sync/driver/about_sync_util.h"
 #include "components/sync/engine/sync_string_conversions.h"
 #include "components/unified_consent/feature.h"
 #include "components/unified_consent/unified_consent_service.h"
-#include "google_apis/gaia/gaia_constants.h"
 #include "services/identity/public/cpp/identity_manager.h"
 #include "services/identity/public/cpp/identity_test_utils.h"
 
@@ -124,35 +116,11 @@
       username_(username),
       password_(password),
       signin_type_(signin_type),
-      oauth2_refesh_token_number_(0),
       profile_debug_name_(profile->GetDebugName()) {}
 
 ProfileSyncServiceHarness::~ProfileSyncServiceHarness() { }
 
-bool ProfileSyncServiceHarness::SetupSync() {
-  bool result = SetupSync(syncer::UserSelectableTypes(), false);
-  if (!result) {
-    LOG(ERROR) << profile_debug_name_ << ": SetupSync failed. Syncer status:\n"
-               << GetServiceStatus();
-  } else {
-    DVLOG(1) << profile_debug_name_ << ": SetupSync successful.";
-  }
-  return result;
-}
-
-bool ProfileSyncServiceHarness::SetupSyncForClearingServerData() {
-  bool result = SetupSync(syncer::UserSelectableTypes(), true);
-  if (!result) {
-    LOG(ERROR) << profile_debug_name_
-               << ": SetupSyncForClear failed. Syncer status:\n"
-               << GetServiceStatus();
-  } else {
-    DVLOG(1) << profile_debug_name_ << ": SetupSyncForClear successful.";
-  }
-  return result;
-}
-
-bool ProfileSyncServiceHarness::SignIn() {
+bool ProfileSyncServiceHarness::SignInPrimaryAccount() {
   // TODO(crbug.com/871221): This function should distinguish primary account
   // (aka sync account) from secondary accounts (content area signin). Let's
   // migrate tests that exercise transport-only sync to secondary accounts.
@@ -203,12 +171,44 @@
   return false;
 }
 
+#if !defined(OS_CHROMEOS)
+void ProfileSyncServiceHarness::SignOutPrimaryAccount() {
+  DCHECK(!username_.empty());
+  identity::ClearPrimaryAccount(
+      SigninManagerFactory::GetForProfile(profile_),
+      IdentityManagerFactory::GetForProfile(profile_),
+      identity::ClearPrimaryAccountPolicy::REMOVE_ALL_ACCOUNTS);
+}
+#endif  // !OS_CHROMEOS
+
+bool ProfileSyncServiceHarness::SetupSync() {
+  bool result = SetupSync(syncer::UserSelectableTypes(), false);
+  if (!result) {
+    LOG(ERROR) << profile_debug_name_ << ": SetupSync failed. Syncer status:\n"
+               << GetServiceStatus();
+  } else {
+    DVLOG(1) << profile_debug_name_ << ": SetupSync successful.";
+  }
+  return result;
+}
+
+bool ProfileSyncServiceHarness::SetupSyncForClearingServerData() {
+  bool result = SetupSync(syncer::UserSelectableTypes(), true);
+  if (!result) {
+    LOG(ERROR) << profile_debug_name_
+               << ": SetupSyncForClear failed. Syncer status:\n"
+               << GetServiceStatus();
+  } else {
+    DVLOG(1) << profile_debug_name_ << ": SetupSyncForClear successful.";
+  }
+  return result;
+}
+
 bool ProfileSyncServiceHarness::SetupSync(syncer::ModelTypeSet synced_datatypes,
                                           bool skip_passphrase_verification) {
   DCHECK(!profile_->IsLegacySupervised())
       << "SetupSync should not be used for legacy supervised users.";
 
-  // Initialize the sync client's profile sync service object.
   if (service() == nullptr) {
     LOG(ERROR) << "SetupSync(): service() is null.";
     return false;
@@ -218,7 +218,7 @@
   // until we've finished configuration.
   sync_blocker_ = service()->GetSetupInProgressHandle();
 
-  if (!SignIn()) {
+  if (!SignInPrimaryAccount()) {
     return false;
   }
 
@@ -235,7 +235,7 @@
     // When unified consent given is set to |true|, the unified consent service
     // enables syncing all datatypes.
     UnifiedConsentServiceFactory::GetForProfile(profile_)
-      ->SetUnifiedConsentGiven(sync_everything);
+        ->SetUnifiedConsentGiven(sync_everything);
     if (!sync_everything) {
       service()->OnUserChoseDatatypes(sync_everything, synced_datatypes);
     }
@@ -291,6 +291,11 @@
   return true;
 }
 
+void ProfileSyncServiceHarness::FinishSyncSetup() {
+  sync_blocker_.reset();
+  service()->SetFirstSetupComplete();
+}
+
 void ProfileSyncServiceHarness::StopSyncService(
     syncer::SyncService::SyncStopDataFate data_fate) {
   DVLOG(1) << "Requesting stop for service.";
@@ -331,17 +336,6 @@
   return true;
 }
 
-#if !defined(OS_CHROMEOS)
-void ProfileSyncServiceHarness::SignoutSyncService() {
-  DCHECK(!username_.empty());
-  // TODO(https://crbug.com/806781): This should go through IdentityManager once
-  // that supports sign-out.
-  SigninManagerFactory::GetForProfile(profile_)->SignOutAndRemoveAllAccounts(
-      signin_metrics::SIGNOUT_TEST,
-      signin_metrics::SignoutDelete::IGNORE_METRIC);
-}
-#endif  // !OS_CHROMEOS
-
 bool ProfileSyncServiceHarness::HasUnsyncedItems() {
   base::RunLoop loop;
   bool result = false;
@@ -362,19 +356,14 @@
   return AwaitQuiescence(harnesses);
 }
 
-bool ProfileSyncServiceHarness::AwaitGroupSyncCycleCompletion(
-    const std::vector<ProfileSyncServiceHarness*>& partners) {
-  return AwaitQuiescence(partners);
-}
-
 // static
 bool ProfileSyncServiceHarness::AwaitQuiescence(
     const std::vector<ProfileSyncServiceHarness*>& clients) {
-  std::vector<ProfileSyncService*> services;
   if (clients.empty()) {
     return true;
   }
 
+  std::vector<ProfileSyncService*> services;
   for (const ProfileSyncServiceHarness* harness : clients) {
     services.push_back(harness->service());
   }
@@ -435,30 +424,6 @@
   return true;
 }
 
-std::string ProfileSyncServiceHarness::GenerateFakeOAuth2RefreshTokenString() {
-  return base::StringPrintf("oauth2_refresh_token_%d",
-                            ++oauth2_refesh_token_number_);
-}
-
-bool ProfileSyncServiceHarness::IsSyncEnabledByUser() const {
-  return service()->IsFirstSetupComplete() &&
-         !service()->HasDisableReason(
-             ProfileSyncService::DISABLE_REASON_USER_CHOICE);
-}
-
-void ProfileSyncServiceHarness::FinishSyncSetup() {
-  sync_blocker_.reset();
-  service()->SetFirstSetupComplete();
-}
-
-SyncCycleSnapshot ProfileSyncServiceHarness::GetLastCycleSnapshot() const {
-  DCHECK(service() != nullptr) << "Sync service has not yet been set up.";
-  if (service()->IsSyncActive()) {
-    return service()->GetLastCycleSnapshot();
-  }
-  return SyncCycleSnapshot();
-}
-
 bool ProfileSyncServiceHarness::EnableSyncForDatatype(
     syncer::ModelType datatype) {
   DVLOG(1) << GetClientInfoString(
@@ -591,6 +556,24 @@
   return true;
 }
 
+SyncCycleSnapshot ProfileSyncServiceHarness::GetLastCycleSnapshot() const {
+  DCHECK(service() != nullptr) << "Sync service has not yet been set up.";
+  if (service()->IsSyncActive()) {
+    return service()->GetLastCycleSnapshot();
+  }
+  return SyncCycleSnapshot();
+}
+
+std::string ProfileSyncServiceHarness::GetServiceStatus() {
+  std::unique_ptr<base::DictionaryValue> value(
+      syncer::sync_ui_util::ConstructAboutInformation(service(),
+                                                      chrome::GetChannel()));
+  std::string service_status;
+  base::JSONWriter::WriteWithOptions(
+      *value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &service_status);
+  return service_status;
+}
+
 // TODO(sync): Clean up this method in a separate CL. Remove all snapshot fields
 // and log shorter, more meaningful messages.
 std::string ProfileSyncServiceHarness::GetClientInfoString(
@@ -622,16 +605,8 @@
   return os.str();
 }
 
-bool ProfileSyncServiceHarness::IsTypePreferred(syncer::ModelType type) {
-  return service()->GetPreferredDataTypes().Has(type);
-}
-
-std::string ProfileSyncServiceHarness::GetServiceStatus() {
-  std::unique_ptr<base::DictionaryValue> value(
-      syncer::sync_ui_util::ConstructAboutInformation(service(),
-                                                      chrome::GetChannel()));
-  std::string service_status;
-  base::JSONWriter::WriteWithOptions(
-      *value, base::JSONWriter::OPTIONS_PRETTY_PRINT, &service_status);
-  return service_status;
+bool ProfileSyncServiceHarness::IsSyncEnabledByUser() const {
+  return service()->IsFirstSetupComplete() &&
+         !service()->HasDisableReason(
+             ProfileSyncService::DISABLE_REASON_USER_CHOICE);
 }
diff --git a/chrome/browser/sync/test/integration/profile_sync_service_harness.h b/chrome/browser/sync/test/integration/profile_sync_service_harness.h
index babc031..82e36cf 100644
--- a/chrome/browser/sync/test/integration/profile_sync_service_harness.h
+++ b/chrome/browser/sync/test/integration/profile_sync_service_harness.h
@@ -41,29 +41,38 @@
       const std::string& username,
       const std::string& password,
       SigninType signin_type);
-  virtual ~ProfileSyncServiceHarness();
+  ~ProfileSyncServiceHarness();
 
-  // Creates a ProfileSyncService for the profile passed at construction and
-  // signs in without actually enabling sync the feature.
-  bool SignIn();
+  // Signs in to a primary account without actually enabling sync the feature.
+  bool SignInPrimaryAccount();
 
-  // Creates a ProfileSyncService for the profile passed at construction and
-  // enables sync for all available datatypes. Returns true only after sync has
-  // been fully initialized and authenticated, and we are ready to process
-  // changes.
+#if !defined(OS_CHROMEOS)
+  // Signs out of the primary account. ChromeOS doesn't have the concept of
+  // sign-out, so this only exists on other platforms.
+  void SignOutPrimaryAccount();
+#endif  // !OS_CHROMEOS
+
+  // Enables and configures sync for all available datatypes. Returns true only
+  // after sync has been fully initialized and authenticated, and we are ready
+  // to process changes.
   bool SetupSync();
 
-  // Setup sync without the authenticating through the passphrase encryption.
+  // Sets up sync without authenticating through the passphrase encryption.
   // Use this method when you need to setup a client that you're going to call
   // StopSyncService(), StartSyncService() directly after.
   bool SetupSyncForClearingServerData();
 
-  // Both SetupSync and SetupSyncForClear call into this method.
+  // Both SetupSync and SetupSyncForClearingServerData call into this method.
   // Same as the above method, but enables sync only for the datatypes contained
   // in |synced_datatypes|.
   bool SetupSync(syncer::ModelTypeSet synced_datatypes,
                  bool skip_passphrase_verification = false);
 
+  // Signals that sync setup is complete, and that PSS may begin syncing.
+  // Typically SetupSync does this automatically, but if that returned false,
+  // then setup may have been left incomplete.
+  void FinishSyncSetup();
+
   // Methods to stop and restart the sync service.
   //
   // For example, this can be used to simulate a sign-in/sign-out or can be
@@ -79,12 +88,6 @@
   // Starts the sync service after a previous stop.
   bool StartSyncService();
 
-#if !defined(OS_CHROMEOS)
-  // Sign out of sync service. ChromeOS doesn't have the concept of sign-out,
-  // so this only exists on other platforms.
-  void SignoutSyncService();
-#endif  // !OS_CHROMEOS
-
   // Returns whether this client has unsynced items. Avoid verifying false
   // return values, because tests typically shouldn't make assumptions about
   // other datatypes.
@@ -99,13 +102,6 @@
   // exactly one client is waiting to receive those changes.
   bool AwaitMutualSyncCycleCompletion(ProfileSyncServiceHarness* partner);
 
-  // Blocks the caller until |this| completes its ongoing sync cycle and every
-  // other client in |partners| have achieved identical download progresses.
-  // Note: Use this method when exactly one client makes local change(s),
-  // and more than one client is waiting to receive those changes.
-  bool AwaitGroupSyncCycleCompletion(
-      const std::vector<ProfileSyncServiceHarness*>& partners);
-
   // Blocks the caller until every client in |clients| completes its ongoing
   // sync cycle and all the clients' progress markers match.  Note: Use this
   // method when more than one client makes local change(s), and more than one
@@ -145,21 +141,6 @@
   // Returns a snapshot of the current sync session.
   syncer::SyncCycleSnapshot GetLastCycleSnapshot() const;
 
-  // Check if |type| is being synced.
-  bool IsTypePreferred(syncer::ModelType type);
-
-  // Returns a string that can be used as the value of an oauth2 refresh token.
-  // This function guarantees that a different string is returned each time
-  // it is called.
-  std::string GenerateFakeOAuth2RefreshTokenString();
-
-  // Returns a string with relevant info about client's sync state (if
-  // available), annotated with |message|. Useful for logging.
-  std::string GetClientInfoString(const std::string& message) const;
-
-  // Signals that sync setup is complete, and that PSS may begin syncing.
-  void FinishSyncSetup();
-
  private:
   ProfileSyncServiceHarness(Profile* profile,
                             const std::string& username,
@@ -169,30 +150,30 @@
   // Gets detailed status from |service_| in pretty-printable form.
   std::string GetServiceStatus();
 
+  // Returns a string with relevant info about client's sync state (if
+  // available), annotated with |message|. Useful for logging.
+  std::string GetClientInfoString(const std::string& message) const;
+
   // Returns true if the user has enabled and configured sync for this client.
   // Note that this does not imply sync is actually running.
   bool IsSyncEnabledByUser() const;
 
-  // Sync profile associated with this sync client.
-  Profile* profile_;
+  // Profile associated with this sync client.
+  Profile* const profile_;
 
   // ProfileSyncService object associated with |profile_|.
-  browser_sync::ProfileSyncService* service_;
+  browser_sync::ProfileSyncService* const service_;
 
   // Prevents Sync from running until configuration is complete.
   std::unique_ptr<syncer::SyncSetupInProgressHandle> sync_blocker_;
 
   // Credentials used for GAIA authentication.
-  std::string username_;
-  std::string password_;
+  const std::string username_;
+  const std::string password_;
 
   // Used to decide what method of profile signin to use.
   const SigninType signin_type_;
 
-  // Number used by GenerateFakeOAuth2RefreshTokenString() to make sure that
-  // all refresh tokens used in the tests are different.
-  int oauth2_refesh_token_number_;
-
   // Used for logging.
   const std::string profile_debug_name_;
 
diff --git a/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc b/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc
index c54f415..592d074 100644
--- a/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_standalone_transport_sync_test.cc
@@ -48,7 +48,7 @@
 
   // Since standalone transport is disabled, signing in should *not* start the
   // Sync machinery.
-  ASSERT_TRUE(GetClient(0)->SignIn());
+  ASSERT_TRUE(GetClient(0)->SignInPrimaryAccount());
   EXPECT_EQ(syncer::SyncService::TransportState::WAITING_FOR_START_REQUEST,
             GetSyncService(0)->GetTransportState());
 }
@@ -66,7 +66,7 @@
   // Signing in (without explicitly setting up Sync) should trigger starting the
   // Sync machinery. Because IsFirstSetupComplete gets set automatically, this
   // will actually start the full Sync feature, not just the transport.
-  ASSERT_TRUE(GetClient(0)->SignIn());
+  ASSERT_TRUE(GetClient(0)->SignInPrimaryAccount());
   EXPECT_EQ(syncer::SyncService::TransportState::INITIALIZING,
             GetSyncService(0)->GetTransportState());
 
@@ -90,7 +90,7 @@
 
   // Signing in (without explicitly setting up Sync) should trigger starting the
   // Sync machinery in standalone transport mode.
-  ASSERT_TRUE(GetClient(0)->SignIn());
+  ASSERT_TRUE(GetClient(0)->SignInPrimaryAccount());
   EXPECT_EQ(syncer::SyncService::TransportState::START_DEFERRED,
             GetSyncService(0)->GetTransportState());
 
diff --git a/chrome/browser/sync/test/integration/single_client_user_consents_sync_test.cc b/chrome/browser/sync/test/integration/single_client_user_consents_sync_test.cc
index fe3eb1aa..d96ce7e 100644
--- a/chrome/browser/sync/test/integration/single_client_user_consents_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_user_consents_sync_test.cc
@@ -44,7 +44,7 @@
       : SingleClientStatusChangeChecker(service), fake_server_(fake_server) {
     for (const UserConsentSpecifics& specifics : expected_specifics) {
       expected_specifics_.insert(std::pair<int64_t, UserConsentSpecifics>(
-          specifics.confirmation_grd_id(), specifics));
+          specifics.consent_case(), specifics));
     }
   }
 
@@ -65,8 +65,7 @@
     // modify |expected_specifics_|.
     for (const SyncEntity& entity : entities) {
       UserConsentSpecifics server_specifics = entity.specifics().user_consent();
-      auto iter =
-          expected_specifics_.find(server_specifics.confirmation_grd_id());
+      auto iter = expected_specifics_.find(server_specifics.consent_case());
       EXPECT_TRUE(expected_specifics_.end() != iter);
       if (expected_specifics_.end() == iter) {
         return false;
@@ -84,6 +83,9 @@
 
  private:
   FakeServer* fake_server_;
+  // TODO(markusheintz): User a string with the serialized proto instead of an
+  // int. The requires creating better expectations with a proper creation
+  // time.
   std::multimap<int64_t, UserConsentSpecifics> expected_specifics_;
 
   DISALLOW_COPY_AND_ASSIGN(UserConsentEqualityChecker);
@@ -122,7 +124,7 @@
   consent_auditor::ConsentAuditor* consent_service =
       ConsentAuditorFactory::GetForProfile(GetProfile(0));
   UserConsentSpecifics specifics;
-  specifics.set_confirmation_grd_id(1);
+  specifics.mutable_sync_consent()->set_confirmation_grd_id(1);
   specifics.set_account_id(GetAccountId());
 
   SyncConsent sync_consent;
@@ -139,7 +141,7 @@
   SetSyncUserConsentSeparateTypeFeature(true);
 
   UserConsentSpecifics specifics;
-  specifics.set_confirmation_grd_id(1);
+  specifics.mutable_sync_consent()->set_confirmation_grd_id(1);
   // Account id may be compared to the synced account, thus, we need them to
   // match.
   specifics.set_account_id(GetAccountId());
@@ -175,7 +177,7 @@
   // We avoid calling SetupSync(), because we don't want to turn on full sync,
   // only sign in such that the standalone transport starts.
   ASSERT_TRUE(SetupClients());
-  ASSERT_TRUE(GetClient(0)->SignIn());
+  ASSERT_TRUE(GetClient(0)->SignInPrimaryAccount());
   ASSERT_TRUE(GetClient(0)->AwaitEngineInitialization());
   ASSERT_TRUE(AwaitQuiescence());
   ASSERT_FALSE(GetSyncService(0)->IsSyncActive())
@@ -193,7 +195,9 @@
       ->RecordSyncConsent(GetAccountId(), sync_consent);
 
   UserConsentSpecifics specifics;
-  specifics.set_confirmation_grd_id(1);
+  SyncConsent* expected_sync_consent = specifics.mutable_sync_consent();
+  expected_sync_consent->set_confirmation_grd_id(1);
+  expected_sync_consent->set_status(UserConsentTypes::GIVEN);
   // Account id may be compared to the synced account, thus, we need them to
   // match.
   specifics.set_account_id(GetAccountId());
diff --git a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
index 0766d400..54b028c 100644
--- a/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
+++ b/chrome/browser/sync/test/integration/single_client_wallet_sync_test.cc
@@ -353,8 +353,15 @@
  protected:
   void RefreshAndWaitForOnPersonalDataChanged(
       autofill::PersonalDataManager* pdm) {
+    WaitForOnPersonalDataChanged(/*should_trigger_refresh=*/true, pdm);
+  }
+
+  void WaitForOnPersonalDataChanged(bool should_trigger_refresh,
+                                    autofill::PersonalDataManager* pdm) {
     pdm->AddObserver(&personal_data_observer_);
-    pdm->Refresh();
+    if (should_trigger_refresh) {
+      pdm->Refresh();
+    }
     base::RunLoop run_loop;
     EXPECT_CALL(personal_data_observer_, OnPersonalDataChanged())
         .WillRepeatedly(QuitMessageLoop(&run_loop));
@@ -412,11 +419,12 @@
 // ChromeOS does not support late signin after profile creation, so the test
 // below does not apply, at least in the current form.
 #if !defined(OS_CHROMEOS)
-// TODO(crbug.com/853688): Reenable once the USS implementation of
-// AUTOFILL_WALLET_DATA (AutofillWalletSyncBridge) has sufficient functionality.
-IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTest,
-                       DISABLED_DownloadAccountStorage_Card) {
-  InitWithFeatures(
+// The account storage requires USS, so we only test the USS implementation
+// here.
+IN_PROC_BROWSER_TEST_F(SingleClientWalletSyncTest,
+                       DownloadAccountStorage_Card) {
+  base::test::ScopedFeatureList features;
+  features.InitWithFeatures(
       /*enabled_features=*/{switches::kSyncStandaloneTransport,
                             switches::kSyncUSSAutofillWalletData,
                             autofill::features::
@@ -424,11 +432,13 @@
       /*disabled_features=*/{});
 
   ASSERT_TRUE(SetupClients());
+  autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
+  pdm->OnSyncServiceInitialized(GetSyncService(0));
 
   GetFakeServer()->SetWalletData(
       {CreateDefaultSyncWalletAddress(), CreateDefaultSyncWalletCard()});
 
-  ASSERT_TRUE(GetClient(0)->SignIn());
+  ASSERT_TRUE(GetClient(0)->SignInPrimaryAccount());
   ASSERT_TRUE(GetClient(0)->AwaitEngineInitialization(
       /*skip_passphrase_verification=*/false));
   ASSERT_TRUE(AwaitQuiescence());
@@ -446,19 +456,32 @@
   EXPECT_EQ(0U, GetServerCards(profile_data).size());
   EXPECT_EQ(0U, GetServerProfiles(profile_data).size());
 
-  // Check that one card and one profile are stored in the account storage.
+  // Check that one card is stored in the account storage.
   EXPECT_EQ(1U, GetServerCards(account_data).size());
-  EXPECT_EQ(1U, GetServerProfiles(account_data).size());
 
-  autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
   ASSERT_NE(nullptr, pdm);
   std::vector<CreditCard*> cards = pdm->GetCreditCards();
   ASSERT_EQ(1uL, cards.size());
-  std::vector<AutofillProfile*> profiles = pdm->GetServerProfiles();
-  ASSERT_EQ(1uL, profiles.size());
 
   ExpectDefaultCreditCardValues(*cards[0]);
-  ExpectDefaultProfileValues(*profiles[0]);
+
+  // Now sign back out.
+  GetClient(0)->SignOutPrimaryAccount();
+
+  // Verify that sync is stopped.
+  ASSERT_EQ(syncer::SyncService::TransportState::DISABLED,
+            GetSyncService(0)->GetTransportState());
+  ASSERT_FALSE(GetSyncService(0)->GetActiveDataTypes().Has(
+      syncer::AUTOFILL_WALLET_DATA));
+
+  // Wait for PDM to receive the data change.
+  WaitForOnPersonalDataChanged(/*should_trigger_refresh=*/false, pdm);
+
+  // Check that the account storage is now cleared.
+  EXPECT_EQ(0U, GetServerCards(account_data).size());
+
+  cards = pdm->GetCreditCards();
+  EXPECT_EQ(0U, cards.size());
 }
 #endif  // !defined(OS_CHROMEOS)
 
@@ -481,6 +504,27 @@
   ASSERT_EQ(0uL, cards.size());
 }
 
+// ChromeOS does not sign out, so the test below does not apply.
+#if !defined(OS_CHROMEOS)
+// Wallet data should get cleared from the database when the user signs out.
+IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTest, ClearOnSignOut) {
+  InitWithDefaultFeatures();
+  GetFakeServer()->SetWalletData(
+      {CreateDefaultSyncWalletAddress(), CreateDefaultSyncWalletCard()});
+  ASSERT_TRUE(SetupSync());
+
+  // Make sure the card is in the DB.
+  autofill::PersonalDataManager* pdm = GetPersonalDataManager(0);
+  ASSERT_NE(nullptr, pdm);
+  ASSERT_EQ(1uL, pdm->GetCreditCards().size());
+
+  // Turn off sync, the card should be gone.
+  GetClient(0)->SignOutPrimaryAccount();
+
+  ASSERT_EQ(0uL, pdm->GetCreditCards().size());
+}
+#endif  // !defined(OS_CHROMEOS)
+
 // Wallet is not using incremental updates. Make sure existing data gets
 // replaced when synced down.
 IN_PROC_BROWSER_TEST_P(SingleClientWalletSyncTest,
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 4d667f1..ace52f0 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -156,7 +156,6 @@
       "cocoa/clickhold_button_cell.mm",
       "cocoa/cocoa_util.h",
       "cocoa/cocoa_util.mm",
-      "cocoa/constrained_web_dialog_delegate_mac.mm",
       "cocoa/constrained_window/constrained_window_alert.h",
       "cocoa/constrained_window/constrained_window_alert.mm",
       "cocoa/constrained_window/constrained_window_button.h",
@@ -283,7 +282,6 @@
       "cocoa/hung_renderer_controller.mm",
       "cocoa/image_button_cell.h",
       "cocoa/image_button_cell.mm",
-      "cocoa/importer/import_lock_dialog_cocoa.mm",
       "cocoa/info_bubble_view.h",
       "cocoa/info_bubble_view.mm",
       "cocoa/info_bubble_window.h",
@@ -346,8 +344,6 @@
       "cocoa/location_bar/translate_decoration.mm",
       "cocoa/location_bar/zoom_decoration.h",
       "cocoa/location_bar/zoom_decoration.mm",
-      "cocoa/login_handler_cocoa.h",
-      "cocoa/login_handler_cocoa.mm",
       "cocoa/main_menu_item.h",
       "cocoa/menu_button.h",
       "cocoa/menu_button.mm",
@@ -403,7 +399,6 @@
       "cocoa/screen_capture_notification_ui_cocoa.mm",
       "cocoa/separate_fullscreen_window.h",
       "cocoa/separate_fullscreen_window.mm",
-      "cocoa/simple_message_box_bridge_views.mm",
       "cocoa/simple_message_box_cocoa.h",
       "cocoa/simple_message_box_cocoa.mm",
       "cocoa/single_web_contents_dialog_manager_cocoa.h",
@@ -595,6 +590,8 @@
     "login/login_interstitial_delegate.h",
     "navigation_correction_tab_observer.cc",
     "navigation_correction_tab_observer.h",
+    "omnibox/query_in_omnibox_factory.cc",
+    "omnibox/query_in_omnibox_factory.h",
     "page_info/page_info.cc",
     "page_info/page_info.h",
     "page_info/page_info_ui.cc",
@@ -1166,8 +1163,6 @@
       "android/view_android_helper.cc",
       "android/view_android_helper.h",
       "browser_otr_state_android.cc",
-      "omnibox/query_in_omnibox_factory.cc",
-      "omnibox/query_in_omnibox_factory.h",
       "screen_capture_notification_ui_stub.cc",
       "webui/eoc_internals/eoc_internals_page_handler.cc",
       "webui/eoc_internals/eoc_internals_page_handler.h",
@@ -1353,7 +1348,6 @@
       "media_router/presentation_receiver_window_controller.cc",
       "media_router/presentation_receiver_window_controller.h",
       "media_router/presentation_receiver_window_delegate.h",
-      "media_router/presentation_receiver_window_factory_mac.cc",
       "media_router/query_result_manager.cc",
       "media_router/query_result_manager.h",
       "media_router/ui_media_sink.cc",
@@ -2250,12 +2244,16 @@
       "views/close_bubble_on_tab_activation_helper.h",
       "views/external_protocol_dialog.cc",
       "views/external_protocol_dialog.h",
+      "views/profiles/avatar_button.cc",
+      "views/profiles/avatar_button.h",
       "views/profiles/badged_profile_photo.cc",
       "views/profiles/badged_profile_photo.h",
       "views/profiles/dice_accounts_menu.cc",
       "views/profiles/dice_accounts_menu.h",
       "views/profiles/profile_chooser_view.cc",
       "views/profiles/profile_chooser_view.h",
+      "views/profiles/user_manager_view.cc",
+      "views/profiles/user_manager_view.h",
       "webui/app_launcher_page_ui.cc",
       "webui/app_launcher_page_ui.h",
       "webui/profile_helper.cc",
@@ -2296,15 +2294,6 @@
       "webui/welcome_ui.h",
     ]
 
-    if (!is_mac || mac_views_browser) {
-      sources += [
-        "views/profiles/avatar_button.cc",
-        "views/profiles/avatar_button.h",
-        "views/profiles/user_manager_view.cc",
-        "views/profiles/user_manager_view.h",
-      ]
-    }
-
     if (enable_dice_support) {
       sources += [
         "webui/signin/dice_turn_sync_on_helper.cc",
@@ -2488,6 +2477,21 @@
       # manage_passwords_decoration.mm
       "passwords/manage_passwords_icon.cc",
       "passwords/manage_passwords_icon.h",
+      "views/apps/chrome_app_window_client_views_mac.mm",
+      "views/certificate_viewer_mac_views.mm",
+      "views/dropdown_bar_host_mac.mm",
+      "views/frame/browser_frame_mac.h",
+      "views/frame/browser_frame_mac.mm",
+      "views/frame/browser_native_widget_window_mac.h",
+      "views/frame/browser_native_widget_window_mac.mm",
+      "views/frame/browser_non_client_frame_view_factory_mac.mm",
+      "views/frame/browser_non_client_frame_view_mac.h",
+      "views/frame/browser_non_client_frame_view_mac.mm",
+      "views/frame/native_browser_frame_factory_mac.mm",
+      "views/infobars/legacy_infobars_mac.cc",
+      "views/tab_contents/chrome_web_contents_view_delegate_views_mac.h",
+      "views/tab_contents/chrome_web_contents_view_delegate_views_mac.mm",
+      "views/tabs/window_finder_mac.mm",
       "web_contents_sizer.mm",
       "webui/help/version_updater_mac.h",
       "webui/help/version_updater_mac.mm",
@@ -2502,6 +2506,7 @@
     deps += [
       "//chrome/app/nibs:localizer_table",
       "//chrome/browser/apps/app_shim",
+      "//extensions/components/native_app_window",
       "//third_party/google_toolbox_for_mac",
       "//third_party/molokocacao",
       "//third_party/mozilla",
@@ -2512,41 +2517,6 @@
       "Carbon.framework",
       "Quartz.framework",
     ]
-
-    if (mac_views_browser) {
-      # MacViews sources that we still want to keep behind a compile-time flag.
-      # TODO(jackhou): Move items to general views sources out of here.
-      sources += [
-        "views/apps/chrome_app_window_client_views_mac.mm",
-        "views/certificate_viewer_mac_views.mm",
-        "views/dropdown_bar_host_mac.mm",
-        "views/frame/browser_frame_mac.h",
-        "views/frame/browser_frame_mac.mm",
-        "views/frame/browser_native_widget_window_mac.h",
-        "views/frame/browser_native_widget_window_mac.mm",
-        "views/frame/browser_non_client_frame_view_factory_mac.mm",
-        "views/frame/browser_non_client_frame_view_mac.h",
-        "views/frame/browser_non_client_frame_view_mac.mm",
-        "views/frame/native_browser_frame_factory_mac.mm",
-        "views/infobars/legacy_infobars_mac.cc",
-        "views/tab_contents/chrome_web_contents_view_delegate_views_mac.h",
-        "views/tab_contents/chrome_web_contents_view_delegate_views_mac.mm",
-        "views/tabs/window_finder_mac.mm",
-      ]
-
-      deps += [ "//extensions/components/native_app_window" ]
-
-      # Truly cocoa-browser-specific sources. These are secondary UI pieces that
-      # are obsolete before mac_views_browser will ever ship, so they aren't
-      # linked in at all.
-      sources -= [
-        "cocoa/constrained_web_dialog_delegate_mac.mm",
-        "cocoa/importer/import_lock_dialog_cocoa.mm",
-        "cocoa/login_handler_cocoa.h",
-        "cocoa/login_handler_cocoa.mm",
-        "cocoa/simple_message_box_bridge_views.mm",
-      ]
-    }
   } else {  # non-Mac.
     sources += [ "web_contents_sizer.cc" ]
   }
@@ -3205,6 +3175,8 @@
         "views/location_bar/selected_keyword_view.h",
         "views/location_bar/star_view.cc",
         "views/location_bar/star_view.h",
+        "views/media_router/cast_dialog_helper.cc",
+        "views/media_router/cast_dialog_helper.h",
         "views/media_router/cast_dialog_metrics.cc",
         "views/media_router/cast_dialog_metrics.h",
         "views/media_router/cast_dialog_no_sinks_view.cc",
@@ -3341,14 +3313,8 @@
       deps += [ "//ui/views:features" ]
 
       if (is_mac) {
-        # This Mac-specific file is being removed in this case because it's only
-        # needed when Views isn't used on Mac.
-        sources -=
-            [ "media_router/presentation_receiver_window_factory_mac.cc" ]
-
         # This source file is compiled out on Mac because there is a
-        # Mac-specific implementation of it that works on mac_views_browser
-        # builds as well:
+        # Mac-specific implementation of it.
         sources -= [ "views/permission_bubble/permission_prompt_impl_views.cc" ]
       }
 
@@ -3855,10 +3821,22 @@
       "extensions/installation_error_infobar_delegate.h",
       "extensions/settings_api_bubble_helpers.cc",
       "extensions/settings_api_bubble_helpers.h",
+      "views/extensions/browser_action_drag_data.cc",
+      "views/extensions/browser_action_drag_data.h",
+      "views/extensions/extension_action_platform_delegate_views.cc",
+      "views/extensions/extension_action_platform_delegate_views.h",
+      "views/extensions/extension_dialog.cc",
+      "views/extensions/extension_dialog.h",
+      "views/extensions/extension_dialog_observer.cc",
+      "views/extensions/extension_dialog_observer.h",
       "views/extensions/extension_popup.cc",
       "views/extensions/extension_popup.h",
       "views/extensions/extension_view_views.cc",
       "views/extensions/extension_view_views.h",
+      "views/extensions/media_galleries_dialog_views.cc",
+      "views/extensions/media_galleries_dialog_views.h",
+      "views/extensions/media_gallery_checkbox_view.cc",
+      "views/extensions/media_gallery_checkbox_view.h",
       "webui/extensions/extension_basic_info.cc",
       "webui/extensions/extension_basic_info.h",
       "webui/extensions/extension_icon_source.cc",
@@ -3868,22 +3846,6 @@
     if (!is_mac) {
       deps += [ "//apps/ui/views" ]
     }
-    if (!is_mac || mac_views_browser) {
-      sources += [
-        "views/extensions/browser_action_drag_data.cc",
-        "views/extensions/browser_action_drag_data.h",
-        "views/extensions/extension_action_platform_delegate_views.cc",
-        "views/extensions/extension_action_platform_delegate_views.h",
-        "views/extensions/extension_dialog.cc",
-        "views/extensions/extension_dialog.h",
-        "views/extensions/extension_dialog_observer.cc",
-        "views/extensions/extension_dialog_observer.h",
-        "views/extensions/media_galleries_dialog_views.cc",
-        "views/extensions/media_galleries_dialog_views.h",
-        "views/extensions/media_gallery_checkbox_view.cc",
-        "views/extensions/media_gallery_checkbox_view.h",
-      ]
-    }
     if (use_aura) {
       sources += [
         "views/chrome_javascript_native_dialog_factory_views.cc",
@@ -4089,8 +4051,10 @@
       "../../test/views/scoped_macviews_browser_mode.cc",
       "../../test/views/scoped_macviews_browser_mode.h",
       "extensions/browser_action_test_util.h",
+      "views/find_bar_host_unittest_util_views.cc",
       "views/payments/test_chrome_payment_request_delegate.cc",
       "views/payments/test_chrome_payment_request_delegate.h",
+      "views/toolbar/browser_action_test_util_views.cc",
       "views/toolbar/browser_action_test_util_views_mac.mm",
       "views/webauthn/authenticator_request_dialog_view_test_api.cc",
       "views/webauthn/authenticator_request_dialog_view_test_api.h",
@@ -4101,12 +4065,6 @@
         "cocoa/find_bar/find_bar_host_unittest_util_cocoa.mm",
       ]
     }
-    if (!is_mac || mac_views_browser) {
-      sources += [
-        "views/find_bar_host_unittest_util_views.cc",
-        "views/toolbar/browser_action_test_util_views.cc",
-      ]
-    }
     if (use_aura) {
       sources += [ "views/toolbar/browser_action_test_util_views_aura.cc" ]
       deps += [
diff --git a/chrome/browser/ui/ash/assistant/assistant_setup.cc b/chrome/browser/ui/ash/assistant/assistant_setup.cc
index b90a47e..d213e948 100644
--- a/chrome/browser/ui/ash/assistant/assistant_setup.cc
+++ b/chrome/browser/ui/ash/assistant/assistant_setup.cc
@@ -179,11 +179,22 @@
                           true);
       }
       break;
+    case ConsentFlowUi::ERROR_ACCOUNT:
+      // Show the opted out mode UI for unsupported Account as they are in opted
+      // out mode.
+      // TODO(llin): we should show a error account message in Opted out UI or
+      // in the onboarding flow.
+      prefs->SetBoolean(arc::prefs::kVoiceInteractionActivityControlAccepted,
+                        false);
+      break;
     case ConsentFlowUi::ALREADY_CONSENTED:
       prefs->SetBoolean(arc::prefs::kVoiceInteractionActivityControlAccepted,
                         true);
       break;
-    default:
+    case ConsentFlowUi::UNSPECIFIED:
+    case ConsentFlowUi::ERROR:
+      prefs->SetBoolean(arc::prefs::kVoiceInteractionActivityControlAccepted,
+                        false);
       LOG(ERROR) << "Invalid activity control consent status.";
   }
 }
diff --git a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
index b09a5f0..4b7d4ab4 100644
--- a/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
+++ b/chrome/browser/ui/ash/multi_user/multi_user_window_manager_chromeos_unittest.cc
@@ -16,6 +16,7 @@
 #include "ash/test_shell_delegate.h"
 #include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
+#include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h"
 #include "ash/wm/tablet_mode/tablet_mode_window_manager.h"
 #include "ash/wm/window_state.h"
 #include "ash/wm/wm_event.h"
@@ -234,19 +235,6 @@
     return UserSwitchAnimatorChromeOS::CoversScreen(window);
   }
 
-  // Create a tablet mode window manager.
-  TabletModeWindowManager* CreateTabletModeWindowManager() {
-    EXPECT_FALSE(tablet_mode_window_manager());
-    Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
-    return tablet_mode_window_manager();
-  }
-
-  TabletModeWindowManager* tablet_mode_window_manager() {
-    return Shell::Get()
-        ->tablet_mode_controller()
-        ->tablet_mode_window_manager_.get();
-  }
-
  private:
   chromeos::ScopedStubInstallAttributes test_install_attributes_;
 
@@ -837,7 +825,9 @@
   EXPECT_FALSE(wm::GetWindowState(window(0))->IsMaximized());
   EXPECT_FALSE(wm::GetWindowState(window(1))->IsMaximized());
 
-  TabletModeWindowManager* manager = CreateTabletModeWindowManager();
+  Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true);
+  TabletModeWindowManager* manager =
+      TabletModeControllerTestApi().tablet_mode_window_manager();
   ASSERT_TRUE(manager);
 
   EXPECT_TRUE(wm::GetWindowState(window(0))->IsMaximized());
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc b/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
index f3d45fb..e7718a9 100644
--- a/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
+++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura.cc
@@ -18,6 +18,7 @@
 #include "content/public/browser/browser_context.h"
 #include "content/public/browser/render_frame_host.h"
 #include "ui/accessibility/ax_action_data.h"
+#include "ui/accessibility/ax_enum_util.h"
 #include "ui/accessibility/ax_enums.mojom.h"
 #include "ui/accessibility/ax_tree_id_registry.h"
 #include "ui/accessibility/platform/aura_window_properties.h"
@@ -97,7 +98,8 @@
     if (active_window) {
       views::AXAuraObjWrapper* focus =
           views::AXAuraObjCache::GetInstance()->GetOrCreate(active_window);
-      SendEvent(context, focus, ax::mojom::Event::kChildrenChanged);
+      if (focus)
+        SendEvent(context, focus, ax::mojom::Event::kChildrenChanged);
     }
   }
   // Gain access to out-of-process native windows.
@@ -120,10 +122,32 @@
   if (!enabled_)
     return;
 
-  views::AXAuraObjWrapper* aura_obj = view ?
-      views::AXAuraObjCache::GetInstance()->GetOrCreate(view) :
-      current_tree_->GetRoot();
-  SendEvent(nullptr, aura_obj, event_type);
+  if (!view) {
+    SendEvent(nullptr, current_tree_->GetRoot(), event_type);
+    return;
+  }
+
+  views::AXAuraObjWrapper* obj =
+      views::AXAuraObjCache::GetInstance()->GetOrCreate(view);
+  if (!obj)
+    return;
+
+  // Post a task to handle the event at the end of the current call stack.
+  // This helps us avoid firing accessibility events for transient changes.
+  // because there's a chance that the underlying object being wrapped could
+  // be deleted, pass the ID of the object rather than the object pointer.
+  int32_t id = obj->GetUniqueId().Get();
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&AutomationManagerAura::SendEventOnObjectById,
+                     weak_ptr_factory_.GetWeakPtr(), id, event_type));
+}
+
+void AutomationManagerAura::SendEventOnObjectById(int32_t id,
+                                                  ax::mojom::Event event_type) {
+  views::AXAuraObjWrapper* obj = views::AXAuraObjCache::GetInstance()->Get(id);
+  if (obj)
+    SendEvent(nullptr, obj, event_type);
 }
 
 void AutomationManagerAura::HandleAlert(content::BrowserContext* context,
@@ -169,7 +193,8 @@
 AutomationManagerAura::AutomationManagerAura()
     : AXHostDelegate(extensions::api::automation::kDesktopTreeID),
       enabled_(false),
-      processing_events_(false) {}
+      processing_events_(false),
+      weak_ptr_factory_(this) {}
 
 AutomationManagerAura::~AutomationManagerAura() {
 }
@@ -185,6 +210,9 @@
 void AutomationManagerAura::SendEvent(BrowserContext* context,
                                       views::AXAuraObjWrapper* aura_obj,
                                       ax::mojom::Event event_type) {
+  if (!enabled_)
+    return;
+
   if (!current_tree_serializer_)
     return;
 
@@ -230,6 +258,9 @@
   AutomationEventRouter* router = AutomationEventRouter::GetInstance();
   router->DispatchAccessibilityEvents(event_bundle);
 
+  if (event_bundle_callback_for_testing_)
+    event_bundle_callback_for_testing_.Run(event_bundle);
+
   processing_events_ = false;
   auto pending_events_copy = pending_events_;
   pending_events_.clear();
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura.h b/chrome/browser/ui/aura/accessibility/automation_manager_aura.h
index edd73882..c947f91 100644
--- a/chrome/browser/ui/aura/accessibility/automation_manager_aura.h
+++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura.h
@@ -13,6 +13,7 @@
 #include <vector>
 
 #include "base/macros.h"
+#include "base/memory/weak_ptr.h"
 #include "chrome/browser/ui/aura/accessibility/ax_tree_source_aura.h"
 #include "ui/accessibility/ax_host_delegate.h"
 #include "ui/accessibility/ax_tree_serializer.h"
@@ -37,6 +38,8 @@
                          ui::AXNodeData,
                          ui::AXTreeData>;
 
+struct ExtensionMsg_AccessibilityEventBundleParams;
+
 // Manages a tree of automation nodes.
 class AutomationManagerAura : public ui::AXHostDelegate,
                               views::AXAuraObjCache::Delegate {
@@ -65,6 +68,12 @@
   void OnEvent(views::AXAuraObjWrapper* aura_obj,
                ax::mojom::Event event_type) override;
 
+  void set_event_bundle_callback_for_testing(
+      base::RepeatingCallback<void(ExtensionMsg_AccessibilityEventBundleParams)>
+          callback) {
+    event_bundle_callback_for_testing_ = callback;
+  }
+
  protected:
   AutomationManagerAura();
   ~AutomationManagerAura() override;
@@ -74,6 +83,8 @@
 
   FRIEND_TEST_ALL_PREFIXES(AutomationManagerAuraBrowserTest, WebAppearsOnce);
 
+  void SendEventOnObjectById(int32_t id, ax::mojom::Event event_type);
+
   // Reset state in this manager. If |reset_serializer| is true, reset the
   // serializer to save memory.
   void Reset(bool reset_serializer);
@@ -101,6 +112,11 @@
   std::vector<std::pair<views::AXAuraObjWrapper*, ax::mojom::Event>>
       pending_events_;
 
+  base::RepeatingCallback<void(ExtensionMsg_AccessibilityEventBundleParams)>
+      event_bundle_callback_for_testing_;
+
+  base::WeakPtrFactory<AutomationManagerAura> weak_ptr_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(AutomationManagerAura);
 };
 
diff --git a/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc b/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc
index 4ab9dd2..fde5645 100644
--- a/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc
+++ b/chrome/browser/ui/aura/accessibility/automation_manager_aura_browsertest.cc
@@ -6,13 +6,18 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
+#include "chrome/common/extensions/chrome_extension_messages.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "chrome/test/views/accessibility_checker.h"
 #include "content/public/browser/browser_accessibility_state.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/test/browser_test_utils.h"
 #include "ui/accessibility/ax_node_data.h"
+#include "ui/views/accessibility/view_accessibility.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/widget.h"
 
 namespace {
 
@@ -39,6 +44,57 @@
   }
 }
 
+// A class that installs a test-only callback to handle automation events
+// from AutomationManagerAura, then waits until an automation event indicates
+// that a given node ID is focused.
+class AutomationEventWaiter {
+ public:
+  explicit AutomationEventWaiter(AutomationManagerAura* manager)
+      : run_loop_(std::make_unique<base::RunLoop>()), weak_factory_(this) {
+    manager->set_event_bundle_callback_for_testing(
+        base::BindRepeating(&AutomationEventWaiter::EventBundleCallback,
+                            weak_factory_.GetWeakPtr()));
+  }
+
+  // Returns immediately if the node with AXAuraObjCache ID |node_id|
+  // has ever been focused, otherwise spins a loop until that node is
+  // focused.
+  void WaitForNodeIdToBeFocused(int node_id) {
+    if (WasNodeIdFocused(node_id))
+      return;
+
+    node_id_to_wait_for_ = node_id;
+    run_loop_->Run();
+    run_loop_.reset(new base::RunLoop);
+  }
+
+  bool WasNodeIdFocused(int node_id) {
+    for (size_t i = 0; i < focused_node_ids_.size(); i++)
+      if (node_id == focused_node_ids_[i])
+        return true;
+    return false;
+  }
+
+ private:
+  // Callback to intercept messages sent by AutomationManagerAura.
+  void EventBundleCallback(
+      ExtensionMsg_AccessibilityEventBundleParams event_bundle) {
+    for (size_t i = 0; i < event_bundle.updates.size(); ++i) {
+      int focused_node_id = event_bundle.updates[i].tree_data.focus_id;
+      focused_node_ids_.push_back(focused_node_id);
+      if (focused_node_id == node_id_to_wait_for_)
+        run_loop_->QuitClosure().Run();
+    }
+  }
+
+  std::unique_ptr<base::RunLoop> run_loop_;
+  int node_id_to_wait_for_ = 0;
+  std::vector<int> focused_node_ids_;
+  base::WeakPtrFactory<AutomationEventWaiter> weak_factory_;
+
+  DISALLOW_COPY_AND_ASSIGN(AutomationEventWaiter);
+};
+
 }  // namespace
 
 typedef InProcessBrowserTest AutomationManagerAuraBrowserTest;
@@ -83,3 +139,60 @@
     }
   }
 }
+
+IN_PROC_BROWSER_TEST_F(AutomationManagerAuraBrowserTest,
+                       TransientFocusChangesAreSuppressed) {
+  AutomationManagerAura* manager = AutomationManagerAura::GetInstance();
+  manager->Enable(browser()->profile());
+
+  views::Widget* widget = new views::Widget;
+  views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW);
+  params.bounds = {0, 0, 200, 200};
+  widget->Init(params);
+  widget->Show();
+  widget->Activate();
+
+  views::AXAuraObjCache* cache = views::AXAuraObjCache::GetInstance();
+  cache->set_focused_widget_for_testing(widget);
+
+  views::View* view1 = new views::View();
+  view1->GetViewAccessibility().OverrideName("view1");
+  view1->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
+  widget->GetRootView()->AddChildView(view1);
+  views::AXAuraObjWrapper* wrapper1 = cache->GetOrCreate(view1);
+  views::View* view2 = new views::View();
+  view2->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
+  view2->GetViewAccessibility().OverrideName("view2");
+  widget->GetRootView()->AddChildView(view2);
+  views::AXAuraObjWrapper* wrapper2 = cache->GetOrCreate(view2);
+  views::View* view3 = new views::View();
+  view3->GetViewAccessibility().OverrideName("view3");
+  view3->SetFocusBehavior(views::View::FocusBehavior::ALWAYS);
+  widget->GetRootView()->AddChildView(view3);
+  views::AXAuraObjWrapper* wrapper3 = cache->GetOrCreate(view3);
+
+  AutomationEventWaiter waiter(manager);
+
+  // Focus view1, then block until we get an accessibility event that
+  // shows this view is focused.
+  view1->RequestFocus();
+  waiter.WaitForNodeIdToBeFocused(wrapper1->GetUniqueId().Get());
+
+  EXPECT_TRUE(waiter.WasNodeIdFocused(wrapper1->GetUniqueId().Get()));
+  EXPECT_FALSE(waiter.WasNodeIdFocused(wrapper2->GetUniqueId().Get()));
+  EXPECT_FALSE(waiter.WasNodeIdFocused(wrapper3->GetUniqueId().Get()));
+
+  // Now focus view2 and then view3. We shouldn't ever get an event
+  // showing view2 as focused, just view3.
+  view2->RequestFocus();
+  view3->RequestFocus();
+  waiter.WaitForNodeIdToBeFocused(wrapper3->GetUniqueId().Get());
+
+  EXPECT_TRUE(waiter.WasNodeIdFocused(wrapper1->GetUniqueId().Get()));
+  EXPECT_FALSE(waiter.WasNodeIdFocused(wrapper2->GetUniqueId().Get()));
+  EXPECT_TRUE(waiter.WasNodeIdFocused(wrapper3->GetUniqueId().Get()));
+
+  cache->set_focused_widget_for_testing(nullptr);
+
+  AddFailureOnWidgetAccessibilityError(widget);
+}
diff --git a/chrome/browser/ui/cocoa/constrained_web_dialog_delegate_mac.mm b/chrome/browser/ui/cocoa/constrained_web_dialog_delegate_mac.mm
deleted file mode 100644
index 2389dfab..0000000
--- a/chrome/browser/ui/cocoa/constrained_web_dialog_delegate_mac.mm
+++ /dev/null
@@ -1,262 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/webui/constrained_web_dialog_delegate_base.h"
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_window.h"
-#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h"
-#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_web_dialog_sheet.h"
-#include "chrome/browser/ui/webui/chrome_web_contents_handler.h"
-#include "content/public/browser/render_view_host.h"
-#include "content/public/browser/web_contents.h"
-#include "content/public/browser/web_contents_observer.h"
-#include "ui/base/cocoa/window_size_constants.h"
-#include "ui/gfx/geometry/size.h"
-#include "ui/web_dialogs/web_dialog_delegate.h"
-#include "ui/web_dialogs/web_dialog_ui.h"
-#include "ui/web_dialogs/web_dialog_web_contents_delegate.h"
-
-using content::WebContents;
-using ui::WebDialogDelegate;
-using ui::WebDialogWebContentsDelegate;
-
-namespace {
-
-class ConstrainedWebDialogDelegateMac;
-
-// This class is to trigger a resize to the dialog window when
-// ResizeDueToAutoResize() is invoked.
-class WebDialogWebContentsDelegateMac
-    : public ui::WebDialogWebContentsDelegate {
- public:
-  WebDialogWebContentsDelegateMac(content::BrowserContext* browser_context,
-                                  content::WebContentsObserver* observer,
-                                  ConstrainedWebDialogDelegateBase* delegate)
-      : ui::WebDialogWebContentsDelegate(browser_context,
-                                         new ChromeWebContentsHandler()),
-        observer_(observer),
-        delegate_(delegate) {
-  }
-  ~WebDialogWebContentsDelegateMac() override {}
-
-  void ResizeDueToAutoResize(content::WebContents* source,
-                             const gfx::Size& preferred_size) override {
-    if (!observer_->web_contents())
-      return;
-    delegate_->ResizeToGivenSize(preferred_size);
-  }
-
- private:
-  // These members must outlive the instance.
-  content::WebContentsObserver* const observer_;
-  ConstrainedWebDialogDelegateBase* delegate_;
-
-  DISALLOW_COPY_AND_ASSIGN(WebDialogWebContentsDelegateMac);
-};
-
-class ConstrainedWebDialogDelegateMac
-    : public ConstrainedWebDialogDelegateBase {
- public:
-  ConstrainedWebDialogDelegateMac(
-      content::BrowserContext* browser_context,
-      WebDialogDelegate* delegate,
-      content::WebContentsObserver* observer)
-      : ConstrainedWebDialogDelegateBase(browser_context, delegate,
-          new WebDialogWebContentsDelegateMac(browser_context, observer,
-                                              this)) {}
-
-  // WebDialogWebContentsDelegate interface.
-  void CloseContents(WebContents* source) override {
-    window_->CloseWebContentsModalDialog();
-  }
-
-  // ConstrainedWebDialogDelegateBase:
-  void ResizeToGivenSize(const gfx::Size size) override {
-    NSSize updated_preferred_size = NSMakeSize(size.width(),
-                                               size.height());
-    [window_->sheet() resizeWithNewSize:updated_preferred_size];
-  }
-
-  void set_window(ConstrainedWindowMac* window) { window_ = window; }
-  ConstrainedWindowMac* window() const { return window_; }
-
- private:
-  // Weak, owned by ConstrainedWebDialogDelegateViewMac.
-  ConstrainedWindowMac* window_;
-
-  DISALLOW_COPY_AND_ASSIGN(ConstrainedWebDialogDelegateMac);
-};
-
-}  // namespace
-
-class ConstrainedWebDialogDelegateViewMac :
-    public ConstrainedWindowMacDelegate,
-    public ConstrainedWebDialogDelegate,
-    public content::WebContentsObserver {
-
- public:
-  ConstrainedWebDialogDelegateViewMac(
-      content::BrowserContext* browser_context,
-      WebDialogDelegate* delegate,
-      content::WebContents* web_contents,
-      const gfx::Size& min_size,
-      const gfx::Size& max_size);
-  ~ConstrainedWebDialogDelegateViewMac() override {}
-
-  // ConstrainedWebDialogDelegate interface
-  const WebDialogDelegate* GetWebDialogDelegate() const override {
-    return impl_->GetWebDialogDelegate();
-  }
-  WebDialogDelegate* GetWebDialogDelegate() override {
-    return impl_->GetWebDialogDelegate();
-  }
-  void OnDialogCloseFromWebUI() override {
-    return impl_->OnDialogCloseFromWebUI();
-  }
-  std::unique_ptr<content::WebContents> ReleaseWebContents() override {
-    return impl_->ReleaseWebContents();
-  }
-  gfx::NativeWindow GetNativeDialog() override { return window_; }
-  WebContents* GetWebContents() override { return impl_->GetWebContents(); }
-  gfx::Size GetConstrainedWebDialogMinimumSize() const override {
-    return min_size_;
-  }
-  gfx::Size GetConstrainedWebDialogMaximumSize() const override {
-    return max_size_;
-  }
-  gfx::Size GetConstrainedWebDialogPreferredSize() const override {
-    gfx::Size size;
-    if (!impl_->closed_via_webui()) {
-      NSRect frame = [window_ frame];
-      size = gfx::Size(frame.size.width, frame.size.height);
-    }
-    return size;
-  }
-
-  // content::WebContentsObserver:
-  void RenderViewCreated(content::RenderViewHost* render_view_host) override {
-    if (IsDialogAutoResizable())
-      EnableAutoResize();
-  }
-  void RenderViewHostChanged(content::RenderViewHost* old_host,
-                             content::RenderViewHost* new_host) override {
-    if (IsDialogAutoResizable())
-      EnableAutoResize();
-  }
-  void DocumentOnLoadCompletedInMainFrame() override {
-    if (IsDialogAutoResizable() && GetWebContents())
-      constrained_window_->ShowWebContentsModalDialog();
-  }
-
-  // ConstrainedWindowMacDelegate interface
-  void OnConstrainedWindowClosed(ConstrainedWindowMac* window) override {
-    if (!impl_->closed_via_webui())
-      GetWebDialogDelegate()->OnDialogClosed("");
-    delete this;
-  }
-
- private:
-  void EnableAutoResize() {
-    if (!GetWebContents())
-      return;
-
-    content::RenderViewHost* render_view_host =
-        GetWebContents()->GetRenderViewHost();
-    render_view_host->EnableAutoResize(min_size_, max_size_);
-  }
-
-  // Whether or not the dialog is autoresizable is determined based on whether
-  // |max_size_| was specified.
-  bool IsDialogAutoResizable() {
-    return !max_size_.IsEmpty();
-  }
-
-  std::unique_ptr<ConstrainedWebDialogDelegateMac> impl_;
-  std::unique_ptr<ConstrainedWindowMac> constrained_window_;
-  base::scoped_nsobject<NSWindow> window_;
-
-  // Minimum and maximum sizes to determine dialog bounds for auto-resizing.
-  const gfx::Size min_size_;
-  const gfx::Size max_size_;
-
-  DISALLOW_COPY_AND_ASSIGN(ConstrainedWebDialogDelegateViewMac);
-};
-
-ConstrainedWebDialogDelegateViewMac::ConstrainedWebDialogDelegateViewMac(
-    content::BrowserContext* browser_context,
-    WebDialogDelegate* delegate,
-    content::WebContents* web_contents,
-    const gfx::Size& min_size,
-    const gfx::Size& max_size)
-    : content::WebContentsObserver(web_contents),
-      impl_(new ConstrainedWebDialogDelegateMac(browser_context, delegate,
-            this)),
-      min_size_(min_size),
-      max_size_(max_size) {
-  if (IsDialogAutoResizable()) {
-    Observe(GetWebContents());
-    EnableAutoResize();
-  }
-
-  // Create a window to hold web_contents in the constrained sheet:
-  gfx::Size size;
-  delegate->GetDialogSize(&size);
-  // The window size for autoresizing dialogs will be determined at a later
-  // time.
-  NSRect frame = IsDialogAutoResizable() ? ui::kWindowSizeDeterminedLater :
-      NSMakeRect(0, 0, size.width(), size.height());
-
-  window_.reset([[ConstrainedWindowCustomWindow alloc]
-                initWithContentRect:frame]);
-  [GetWebContents()->GetNativeView() setFrame:frame];
-  [GetWebContents()->GetNativeView() setAutoresizingMask:
-      NSViewWidthSizable|NSViewHeightSizable];
-  [[window_ contentView] addSubview:GetWebContents()->GetNativeView()];
-
-  base::scoped_nsobject<WebDialogConstrainedWindowSheet> sheet(
-      [[WebDialogConstrainedWindowSheet alloc] initWithCustomWindow:window_
-                                                  webDialogDelegate:delegate]);
-
-  if (IsDialogAutoResizable()) {
-    constrained_window_ = CreateWebModalDialogMac(
-        this, web_contents, sheet);
-  } else {
-    constrained_window_ = CreateAndShowWebModalDialogMac(
-        this, web_contents, sheet);
-  }
-
-  impl_->set_window(constrained_window_.get());
-}
-
-ConstrainedWebDialogDelegate* ShowConstrainedWebDialog(
-        content::BrowserContext* browser_context,
-        WebDialogDelegate* delegate,
-        content::WebContents* web_contents) {
-  // Deleted when the dialog closes.
-  ConstrainedWebDialogDelegateViewMac* constrained_delegate =
-      new ConstrainedWebDialogDelegateViewMac(
-          browser_context, delegate, web_contents,
-          gfx::Size(), gfx::Size());
-  return constrained_delegate;
-}
-
-ConstrainedWebDialogDelegate* ShowConstrainedWebDialogWithAutoResize(
-    content::BrowserContext* browser_context,
-    WebDialogDelegate* delegate,
-    content::WebContents* web_contents,
-    const gfx::Size& min_size,
-    const gfx::Size& max_size) {
-  DCHECK(!min_size.IsEmpty());
-  DCHECK(!max_size.IsEmpty());
-  // Deleted when the dialog closes.
-  ConstrainedWebDialogDelegateViewMac* constrained_delegate =
-      new ConstrainedWebDialogDelegateViewMac(
-          browser_context, delegate, web_contents,
-          min_size, max_size);
-  return constrained_delegate;
-}
diff --git a/chrome/browser/ui/cocoa/importer/import_lock_dialog_cocoa.mm b/chrome/browser/ui/cocoa/importer/import_lock_dialog_cocoa.mm
deleted file mode 100644
index 8405726..0000000
--- a/chrome/browser/ui/cocoa/importer/import_lock_dialog_cocoa.mm
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import <Cocoa/Cocoa.h>
-
-#include "base/bind.h"
-#include "base/callback.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/metrics/user_metrics.h"
-#include "base/threading/thread_task_runner_handle.h"
-#include "chrome/browser/importer/importer_lock_dialog.h"
-#include "chrome/browser/ui/cocoa/browser_dialogs_views_mac.h"
-#include "chrome/grit/chromium_strings.h"
-#include "chrome/grit/generated_resources.h"
-#include "components/strings/grit/components_strings.h"
-#include "ui/base/l10n/l10n_util_mac.h"
-
-using base::UserMetricsAction;
-
-namespace importer {
-
-void ShowImportLockDialog(gfx::NativeWindow parent,
-                          const base::Callback<void(bool)>& callback) {
-  if (chrome::ShowAllDialogsWithViewsToolkit())
-    return chrome::ShowImportLockDialogViews(parent, callback);
-
-  base::scoped_nsobject<NSAlert> lock_alert([[NSAlert alloc] init]);
-  [lock_alert addButtonWithTitle:l10n_util::GetNSStringWithFixup(
-      IDS_IMPORTER_LOCK_OK)];
-  [lock_alert addButtonWithTitle:l10n_util::GetNSStringWithFixup(IDS_CANCEL)];
-  [lock_alert setInformativeText:l10n_util::GetNSStringWithFixup(
-      IDS_IMPORTER_LOCK_TEXT)];
-  [lock_alert setMessageText:l10n_util::GetNSStringWithFixup(
-      IDS_IMPORTER_LOCK_TITLE)];
-
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::Bind(callback, [lock_alert runModal] == NSAlertFirstButtonReturn));
-  base::RecordAction(UserMetricsAction("ImportLockDialogCocoa_Shown"));
-}
-
-}  // namespace importer
diff --git a/chrome/browser/ui/cocoa/login_handler_cocoa.h b/chrome/browser/ui/cocoa/login_handler_cocoa.h
deleted file mode 100644
index c2543c51..0000000
--- a/chrome/browser/ui/cocoa/login_handler_cocoa.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_UI_COCOA_LOGIN_HANDLER_COCOA_H_
-#define CHROME_BROWSER_UI_COCOA_LOGIN_HANDLER_COCOA_H_
-
-#import <Cocoa/Cocoa.h>
-
-class LoginHandlerMac;
-
-// Controller of the sheet used by LoginHandlerMac. Interface Builder wants
-// this to be in a .h file.
-@interface LoginHandlerSheet : NSWindowController {
- @private
-  IBOutlet NSTextField* nameField_;
-  IBOutlet NSSecureTextField* passwordField_;
-  IBOutlet NSTextField* authorityField_;
-  IBOutlet NSTextField* explanationField_;
-  IBOutlet NSButton* loginButton_;
-  IBOutlet NSButton* cancelButton_;
-  LoginHandlerMac* handler_;  // weak, owns us
-}
-- (id)initWithLoginHandler:(LoginHandlerMac*)handler;
-- (IBAction)loginPressed:(id)sender;
-- (IBAction)cancelPressed:(id)sender;
-- (void)autofillLogin:(NSString*)login password:(NSString*)password;
-- (void)setAuthority:(NSString*)authority;
-- (void)setExplanation:(NSString*)explanation;
-@end
-
-#endif  // CHROME_BROWSER_UI_COCOA_LOGIN_HANDLER_COCOA_H_
diff --git a/chrome/browser/ui/cocoa/login_handler_cocoa.mm b/chrome/browser/ui/cocoa/login_handler_cocoa.mm
deleted file mode 100644
index b947f7a..0000000
--- a/chrome/browser/ui/cocoa/login_handler_cocoa.mm
+++ /dev/null
@@ -1,216 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "chrome/browser/ui/cocoa/login_handler_cocoa.h"
-
-#include "base/mac/bundle_locations.h"
-#include "base/mac/scoped_nsobject.h"
-#include "base/macros.h"
-#include "base/optional.h"
-#include "base/strings/string16.h"
-#include "base/strings/string_util.h"
-#include "base/strings/sys_string_conversions.h"
-#include "base/strings/utf_string_conversions.h"
-#include "chrome/browser/tab_contents/tab_util.h"
-#include "chrome/browser/ui/browser_dialogs.h"
-#include "chrome/browser/ui/cocoa/browser_dialogs_views_mac.h"
-#import "chrome/browser/ui/cocoa/constrained_window/constrained_window_custom_sheet.h"
-#include "chrome/browser/ui/cocoa/constrained_window/constrained_window_mac.h"
-#include "chrome/browser/ui/login/login_handler.h"
-#include "components/password_manager/core/browser/login_model.h"
-#include "components/password_manager/core/browser/password_manager.h"
-#include "content/public/browser/browser_thread.h"
-#include "content/public/browser/web_contents.h"
-#include "third_party/google_toolbox_for_mac/src/AppKit/GTMUILocalizerAndLayoutTweaker.h"
-
-using autofill::PasswordForm;
-using content::BrowserThread;
-using content::WebContents;
-
-// ----------------------------------------------------------------------------
-// LoginHandlerMac
-
-// This class simply forwards the authentication from the LoginView (on
-// the UI thread) to the net::URLRequest (on the I/O thread).
-// This class uses ref counting to ensure that it lives until all InvokeLaters
-// have been called.
-class LoginHandlerMac : public LoginHandler,
-                        public ConstrainedWindowMacDelegate {
- public:
-  LoginHandlerMac(
-      net::AuthChallengeInfo* auth_info,
-      content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
-      LoginAuthRequiredCallback auth_required_callback)
-      : LoginHandler(auth_info,
-                     web_contents_getter,
-                     std::move(auth_required_callback)) {}
-
-  // LoginModelObserver implementation.
-  void OnAutofillDataAvailableInternal(
-      const base::string16& username,
-      const base::string16& password) override {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-    [sheet_controller_ autofillLogin:base::SysUTF16ToNSString(username)
-                            password:base::SysUTF16ToNSString(password)];
-  }
-  void OnLoginModelDestroying() override {}
-
-  // LoginHandler:
-  void BuildViewImpl(const base::string16& authority,
-                     const base::string16& explanation,
-                     LoginModelData* login_model_data) override {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
-    sheet_controller_.reset(
-        [[LoginHandlerSheet alloc] initWithLoginHandler:this]);
-
-    if (login_model_data)
-      SetModel(*login_model_data);
-    else
-      ResetModel();
-
-    [sheet_controller_ setAuthority:base::SysUTF16ToNSString(authority)];
-    [sheet_controller_ setExplanation:base::SysUTF16ToNSString(explanation)];
-
-    // Scary thread safety note: This can potentially be called *after* SetAuth
-    // or CancelAuth (say, if the request was cancelled before the UI thread got
-    // control).  However, that's OK since any UI interaction in those functions
-    // will occur via an InvokeLater on the UI thread, which is guaranteed
-    // to happen after this is called (since this was InvokeLater'd first).
-    WebContents* requesting_contents = GetWebContentsForLogin();
-    DCHECK(requesting_contents);
-
-    base::scoped_nsobject<CustomConstrainedWindowSheet> sheet(
-        [[CustomConstrainedWindowSheet alloc]
-            initWithCustomWindow:[sheet_controller_ window]]);
-    constrained_window_ = CreateAndShowWebModalDialogMac(
-        this, requesting_contents, sheet);
-
-    NotifyAuthNeeded();
-  }
-
-  void CloseDialog() override {
-    // The hosting dialog may have been freed.
-    if (constrained_window_)
-      constrained_window_->CloseWebContentsModalDialog();
-  }
-
-  // Overridden from ConstrainedWindowMacDelegate:
-  void OnConstrainedWindowClosed(ConstrainedWindowMac* window) override {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
-    ResetModel();
-    ReleaseSoon();
-
-    constrained_window_.reset();
-    sheet_controller_.reset();
-  }
-
-  void OnLoginPressed(const base::string16& username,
-                      const base::string16& password) {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
-    SetAuth(username, password);
-  }
-
-  void OnCancelPressed() {
-    DCHECK_CURRENTLY_ON(BrowserThread::UI);
-    CancelAuth();
-  }
-
- private:
-  friend class LoginPrompt;
-
-  ~LoginHandlerMac() override {
-    // This class will be deleted on a non UI thread. Ensure that the UI members
-    // have already been deleted.
-    CHECK(!constrained_window_.get());
-    CHECK(!sheet_controller_.get());
-  }
-
-  // The Cocoa controller of the GUI.
-  base::scoped_nsobject<LoginHandlerSheet> sheet_controller_;
-
-  std::unique_ptr<ConstrainedWindowMac> constrained_window_;
-
-  DISALLOW_COPY_AND_ASSIGN(LoginHandlerMac);
-};
-
-// static
-scoped_refptr<LoginHandler> LoginHandler::Create(
-    net::AuthChallengeInfo* auth_info,
-    content::ResourceRequestInfo::WebContentsGetter web_contents_getter,
-    LoginAuthRequiredCallback auth_required_callback) {
-  return chrome::CreateLoginHandlerViews(auth_info, web_contents_getter,
-                                         std::move(auth_required_callback));
-}
-
-// ----------------------------------------------------------------------------
-// LoginHandlerSheet
-
-@implementation LoginHandlerSheet
-
-- (id)initWithLoginHandler:(LoginHandlerMac*)handler {
-  NSString* nibPath =
-      [base::mac::FrameworkBundle() pathForResource:@"HttpAuthLoginSheet"
-                                             ofType:@"nib"];
-  if ((self = [super initWithWindowNibPath:nibPath
-                                     owner:self])) {
-    handler_ = handler;
-    // Force the nib to load so that all outlets are initialized.
-    [self window];
-  }
-  return self;
-}
-
-- (void)dealloc {
-  // The buttons could be in a modal loop, so disconnect them so they cannot
-  // call back to us after we're dead.
-  [loginButton_ setTarget:nil];
-  [cancelButton_ setTarget:nil];
-  [super dealloc];
-}
-
-- (IBAction)loginPressed:(id)sender {
-  handler_->OnLoginPressed(
-      base::SysNSStringToUTF16([nameField_ stringValue]),
-      base::SysNSStringToUTF16([passwordField_ stringValue]));
-}
-
-- (IBAction)cancelPressed:(id)sender {
-  handler_->OnCancelPressed();
-}
-
-- (void)autofillLogin:(NSString*)login password:(NSString*)password {
-  if ([[nameField_ stringValue] length] == 0) {
-    [nameField_ setStringValue:login];
-    [passwordField_ setStringValue:password];
-    [nameField_ selectText:self];
-  }
-}
-
-- (void)setAuthority:(NSString*)authority {
-  [authorityField_ setStringValue:authority];
-
-  // Resize the text field.
-  CGFloat windowDelta = [GTMUILocalizerAndLayoutTweaker
-      sizeToFitFixedWidthTextField:authorityField_];
-
-  NSRect newFrame = [[self window] frame];
-  newFrame.size.height += windowDelta;
-  [[self window] setFrame:newFrame display:NO];
-}
-
-- (void)setExplanation:(NSString*)explanation {
-  [explanationField_ setStringValue:explanation];
-
-  // Resize the text field.
-  CGFloat windowDelta = [GTMUILocalizerAndLayoutTweaker
-       sizeToFitFixedWidthTextField:explanationField_];
-
-  NSRect newFrame = [[self window] frame];
-  newFrame.size.height += windowDelta;
-  [[self window] setFrame:newFrame display:NO];
-}
-
-@end
diff --git a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
index beb982f..8b9807f4 100644
--- a/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
+++ b/chrome/browser/ui/cocoa/omnibox/omnibox_view_mac.mm
@@ -608,7 +608,7 @@
   AnnounceAutocompleteForScreenReader(
       AutocompleteMatchType::ToAccessibilityLabel(
           match, display_text, model()->popup_model()->selected_line(),
-          model()->result().size()));
+          model()->result().size(), false));
 }
 
 bool OmniboxViewMac::OnInlineAutocompleteTextMaybeChanged(
diff --git a/chrome/browser/ui/cocoa/simple_message_box_bridge_views.mm b/chrome/browser/ui/cocoa/simple_message_box_bridge_views.mm
deleted file mode 100644
index 96a692e..0000000
--- a/chrome/browser/ui/cocoa/simple_message_box_bridge_views.mm
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "base/callback.h"
-#include "base/message_loop/message_loop.h"
-#include "base/run_loop.h"
-#include "chrome/browser/ui/cocoa/browser_dialogs_views_mac.h"
-#include "chrome/browser/ui/cocoa/simple_message_box_cocoa.h"
-#include "chrome/browser/ui/simple_message_box.h"
-#include "chrome/browser/ui/views/simple_message_box_views.h"
-#include "ui/base/resource/resource_bundle.h"
-
-namespace {
-
-chrome::MessageBoxResult ShowMessageBoxImpl(
-    gfx::NativeWindow parent,
-    const base::string16& title,
-    const base::string16& message,
-    chrome::MessageBoxType type,
-    const base::string16& yes_text,
-    const base::string16& no_text,
-    const base::string16& checkbox_text) {
-  // These functions may be called early in browser startup, in which case the
-  // UI thread may not be ready to run or configured fully. In that case, fall
-  // back to native Cocoa message boxes.
-  if (base::MessageLoopForUI::IsCurrent() &&
-      base::RunLoop::IsRunningOnCurrentThread() &&
-      ui::ResourceBundle::HasSharedInstance() &&
-      chrome::ShowAllDialogsWithViewsToolkit()) {
-    return SimpleMessageBoxViews::Show(parent, title, message, type, yes_text,
-                                       no_text, checkbox_text);
-  }
-  // ShowMessageBoxCocoa() and NSAlerts in general don't support most of the
-  // above options at all.
-  return chrome::ShowMessageBoxCocoa(message, type, checkbox_text);
-}
-
-}  // namespace
-
-namespace chrome {
-
-void ShowWarningMessageBox(gfx::NativeWindow parent,
-                           const base::string16& title,
-                           const base::string16& message) {
-  ShowMessageBoxImpl(parent, title, message, MESSAGE_BOX_TYPE_WARNING,
-                     base::string16(), base::string16(), base::string16());
-}
-
-void ShowWarningMessageBoxWithCheckbox(
-    gfx::NativeWindow parent,
-    const base::string16& title,
-    const base::string16& message,
-    const base::string16& checkbox_text,
-    base::OnceCallback<void(bool checked)> callback) {
-  MessageBoxResult result =
-      ShowMessageBoxImpl(parent, title, message, MESSAGE_BOX_TYPE_WARNING,
-                         base::string16(), base::string16(), checkbox_text);
-  std::move(callback).Run(result == MESSAGE_BOX_RESULT_YES);
-}
-
-MessageBoxResult ShowQuestionMessageBox(gfx::NativeWindow parent,
-                                        const base::string16& title,
-                                        const base::string16& message) {
-  return ShowMessageBoxImpl(parent, title, message, MESSAGE_BOX_TYPE_QUESTION,
-                            base::string16(), base::string16(),
-                            base::string16());
-}
-
-}  // namespace chrome
diff --git a/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.h b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.h
index 9ed29bd..33f7ec10 100644
--- a/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.h
+++ b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.h
@@ -37,7 +37,7 @@
 
 // Creates a NSCandidateListTouchBarItem that contains text suggestions
 // based on the current text selection.
-- (NSCandidateListTouchBarItem*)createCandidateListItem
+- (NSCandidateListTouchBarItem*)makeCandidateListItem
     API_AVAILABLE(macos(10.12.2));
 
 - (void)candidateListTouchBarItem:(NSCandidateListTouchBarItem*)anItem
@@ -77,4 +77,4 @@
 
 @end
 
-#endif  // CHROME_BROWSER_UI_COCOA_TOUCHBAR_SUGGESTED_TEXT_TOUCH_BAR_CONTROLLER_H_
\ No newline at end of file
+#endif  // CHROME_BROWSER_UI_COCOA_TOUCHBAR_SUGGESTED_TEXT_TOUCH_BAR_CONTROLLER_H_
diff --git a/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.mm b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.mm
index 471a2da1..a88943c 100644
--- a/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.mm
+++ b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller.mm
@@ -126,23 +126,23 @@
   if (![identifier hasSuffix:kTextSuggestionsItemsTouchId])
     return nil;
 
-  return [self createCandidateListItem];
+  return [self makeCandidateListItem];
 }
 
-- (NSCandidateListTouchBarItem*)createCandidateListItem {
-  NSCandidateListTouchBarItem* candidateListItem =
+- (NSCandidateListTouchBarItem*)makeCandidateListItem {
+  base::scoped_nsobject<NSCandidateListTouchBarItem> candidateListItem(
       [[NSCandidateListTouchBarItem alloc]
-          initWithIdentifier:kTextSuggestionsItemsTouchId];
+          initWithIdentifier:kTextSuggestionsItemsTouchId]);
 
-  candidateListItem.delegate = self;
+  [candidateListItem setDelegate:self];
   if (selectionRange_.length)
-    candidateListItem.collapsed = YES;
+    [candidateListItem setCollapsed:YES];
 
   [candidateListItem setCandidates:suggestions_
                   forSelectedRange:selectionRange_
                           inString:text_];
 
-  return candidateListItem;
+  return candidateListItem.autorelease();
 }
 
 - (void)candidateListTouchBarItem:(NSCandidateListTouchBarItem*)anItem
@@ -173,19 +173,27 @@
       return;
     }
 
-    if (!range.IsValid()) {
-      [self updateTextSelection:base::string16() range:gfx::Range() offset:0];
+    // TODO(crbug.com/880642): It's possible for a range out of the text bounds
+    // to be passed in. Investigate this.
+    if (range.start() - offset > text.length() ||
+        range.end() - offset > text.length()) {
+      text_.reset([[NSString alloc] init]);
+      selectionRange_ = NSMakeRange(0, 0);
+      editingWordRange_ = NSMakeRange(0, 0);
+      offsetEditingWordRange_ = NSMakeRange(0, 0);
       return;
     }
 
     text_.reset([base::SysUTF16ToNSString(text) retain]);
-    selectionRange_ =
-        NSMakeRange(range.start() - offset, range.end() - range.start());
+    selectionRange_ = range.ToNSRange();
+    selectionRange_.location -= offset;
+
     editingWordRange_ =
         [self editingWordRangeFromText:text
                         cursorPosition:selectionRange_.location];
-    offsetEditingWordRange_ = NSMakeRange(editingWordRange_.location + offset,
-                                          editingWordRange_.length);
+
+    offsetEditingWordRange_ = editingWordRange_;
+    offsetEditingWordRange_.location += offset;
     [self requestSuggestions];
   }
 }
diff --git a/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_browsertest.mm b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_browsertest.mm
index 95254cc..8172a5a7 100644
--- a/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_browsertest.mm
+++ b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_browsertest.mm
@@ -191,15 +191,24 @@
   }
 }
 
-// Tests that an invalid range does not crash the controller.
-IN_PROC_BROWSER_TEST_F(TextSuggestionsTouchBarControllerTest, InvalidRange) {
+// Tests that a range outside of the text bounds will set the selection range
+// to empty.
+IN_PROC_BROWSER_TEST_F(TextSuggestionsTouchBarControllerTest,
+                       RangeOutOfTextBounds) {
   FocusTextfield();
   [touch_bar_controller_ setText:@""];
   [touch_bar_controller_ setSelectionRange:gfx::Range()];
 
   [touch_bar_controller_
       updateTextSelection:base::string16(base::ASCIIToUTF16("text"))
-                    range:gfx::Range::InvalidRange()
+                    range:gfx::Range(4, 5)
+                   offset:0];
+  EXPECT_STREQ("", [touch_bar_controller_ text].UTF8String);
+  EXPECT_EQ(gfx::Range(), [touch_bar_controller_ selectionRange]);
+
+  [touch_bar_controller_
+      updateTextSelection:base::string16(base::ASCIIToUTF16("text"))
+                    range:gfx::Range(2, 5)
                    offset:0];
   EXPECT_STREQ("", [touch_bar_controller_ text].UTF8String);
   EXPECT_EQ(gfx::Range(), [touch_bar_controller_ selectionRange]);
diff --git a/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_unittest.mm b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_unittest.mm
index 7bc5975..1752bec06 100644
--- a/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_unittest.mm
+++ b/chrome/browser/ui/cocoa/touchbar/text_suggestions_touch_bar_controller_unittest.mm
@@ -38,15 +38,11 @@
 // Tests that the NSCandidateListTouchBarItem collapses properly.
 TEST_F(TextSuggestionsTouchBarControllerTest, CollapsedCandidateList) {
   if (@available(macOS 10.12.2, *)) {
-    base::scoped_nsobject<NSCandidateListTouchBarItem> item;
-
     [controller_ setSelectionRange:gfx::Range()];
-    item.reset([controller_ createCandidateListItem]);
-    EXPECT_FALSE([item isCollapsed]);
+    EXPECT_FALSE([[controller_ makeCandidateListItem] isCollapsed]);
 
     [controller_ setSelectionRange:gfx::Range(0, 1)];
-    item.reset([controller_ createCandidateListItem]);
-    EXPECT_TRUE([item isCollapsed]);
+    EXPECT_TRUE([[controller_ makeCandidateListItem] isCollapsed]);
   }
 }
 
@@ -142,4 +138,4 @@
     histogram_tester.ExpectBucketCount("TouchBar.Default.Metrics",
                                        ui::TouchBarAction::TEXT_SUGGESTION, 1);
   }
-}
\ No newline at end of file
+}
diff --git a/chrome/browser/ui/media_router/presentation_receiver_window_factory_mac.cc b/chrome/browser/ui/media_router/presentation_receiver_window_factory_mac.cc
deleted file mode 100644
index 773012f..0000000
--- a/chrome/browser/ui/media_router/presentation_receiver_window_factory_mac.cc
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/ui/media_router/presentation_receiver_window.h"
-
-#include "base/logging.h"
-
-// static
-PresentationReceiverWindow* PresentationReceiverWindow::Create(
-    PresentationReceiverWindowDelegate* delegate,
-    const gfx::Rect& bounds) {
-  NOTREACHED();
-  return nullptr;
-}
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
index aaad2f0..b6a1df04 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.cc
@@ -39,6 +39,7 @@
 #include "chrome/browser/ui/layout_constants.h"
 #include "chrome/browser/ui/omnibox/chrome_omnibox_edit_controller.h"
 #include "chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer.h"
+#include "chrome/browser/ui/omnibox/query_in_omnibox_factory.h"
 #include "chrome/browser/ui/search/search_tab_helper.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/common/search/instant_types.h"
@@ -222,6 +223,10 @@
   return AutocompleteClassifierFactory::GetForProfile(profile_);
 }
 
+QueryInOmnibox* ChromeOmniboxClient::GetQueryInOmnibox() {
+  return QueryInOmniboxFactory::GetForProfile(profile_);
+}
+
 gfx::Image ChromeOmniboxClient::GetIconIfExtensionMatch(
     const AutocompleteMatch& match) const {
   TemplateURLService* service =
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_client.h b/chrome/browser/ui/omnibox/chrome_omnibox_client.h
index d82a6fda..baa974a 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_client.h
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_client.h
@@ -49,6 +49,7 @@
   TemplateURLService* GetTemplateURLService() override;
   const AutocompleteSchemeClassifier& GetSchemeClassifier() const override;
   AutocompleteClassifier* GetAutocompleteClassifier() override;
+  QueryInOmnibox* GetQueryInOmnibox() override;
   gfx::Image GetIconIfExtensionMatch(
       const AutocompleteMatch& match) const override;
   gfx::Image GetSizedIcon(const gfx::VectorIcon& vector_icon_type,
diff --git a/chrome/browser/ui/search/instant_theme_browsertest.cc b/chrome/browser/ui/search/instant_theme_browsertest.cc
index 7f55eb9..2a43e21 100644
--- a/chrome/browser/ui/search/instant_theme_browsertest.cc
+++ b/chrome/browser/ui/search/instant_theme_browsertest.cc
@@ -6,13 +6,18 @@
 #include "chrome/browser/chrome_notification_types.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/search/instant_service.h"
+#include "chrome/browser/search/instant_service_factory.h"
+#include "chrome/browser/search/instant_service_observer.h"
 #include "chrome/browser/themes/theme_service.h"
 #include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/search/instant_test_base.h"
 #include "chrome/browser/ui/search/instant_test_utils.h"
+#include "chrome/browser/ui/search/local_ntp_test_utils.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/browser/ui/webui/theme_source.h"
+#include "chrome/common/search/instant_types.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
@@ -24,6 +29,50 @@
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
+class TestThemeInfoObserver : public InstantServiceObserver {
+ public:
+  explicit TestThemeInfoObserver(InstantService* service) : service_(service) {
+    service_->AddObserver(this);
+  }
+
+  ~TestThemeInfoObserver() override { service_->RemoveObserver(this); }
+
+  void WaitForThemeApplied(bool theme_installed) {
+    DCHECK(!quit_closure_);
+
+    theme_installed_ = theme_installed;
+    if (!theme_info_.using_default_theme == theme_installed) {
+      return;
+    }
+
+    base::RunLoop run_loop;
+    quit_closure_ = run_loop.QuitClosure();
+    run_loop.Run();
+  }
+
+  bool IsUsingDefaultTheme() { return theme_info_.using_default_theme; }
+
+ private:
+  void ThemeInfoChanged(const ThemeBackgroundInfo& theme_info) override {
+    theme_info_ = theme_info;
+
+    if (quit_closure_ && !theme_info_.using_default_theme == theme_installed_) {
+      std::move(quit_closure_).Run();
+      quit_closure_.Reset();
+    }
+  }
+
+  void MostVisitedItemsChanged(const std::vector<InstantMostVisitedItem>&,
+                               bool is_custom_links) override {}
+
+  InstantService* const service_;
+
+  ThemeBackgroundInfo theme_info_;
+
+  bool theme_installed_;
+  base::OnceClosure quit_closure_;
+};
+
 class InstantThemeTest : public extensions::ExtensionBrowserTest,
                          public InstantTestBase {
  public:
@@ -117,84 +166,147 @@
   EXPECT_TRUE(loaded) << search_url;
 }
 
-// Flaky on all bots. http://crbug.com/335297.
-IN_PROC_BROWSER_TEST_F(InstantThemeTest,
-                       DISABLED_NoThemeBackgroundChangeEventOnTabSwitch) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-
-  // Install a theme.
-  ASSERT_NO_FATAL_FAILURE(InstallThemeAndVerify("theme", "camo theme"));
+IN_PROC_BROWSER_TEST_F(InstantThemeTest, ThemeAppliedToExistingTab) {
+  // On the existing tab.
   ASSERT_EQ(1, browser()->tab_strip_model()->count());
-
-  // Open new tab.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(), GURL(chrome::kChromeUINewTabURL),
-      WindowOpenDisposition::NEW_FOREGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB |
-          ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
-  ASSERT_EQ(2, browser()->tab_strip_model()->count());
-
-  // Make sure the tab did not receive an onthemechange event for the
-  // already-installed theme. (An event *is* sent, but that happens before the
-  // page can register its handler.)
-  content::WebContents* active_tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
-  ASSERT_EQ(1, browser()->tab_strip_model()->active_index());
-  int on_theme_changed_calls = 0;
-  ASSERT_TRUE(instant_test_utils::GetIntFromJS(
-      active_tab, "onThemeChangedCalls", &on_theme_changed_calls));
-  EXPECT_EQ(0, on_theme_changed_calls);
-
-  // Activate the previous tab.
-  browser()->tab_strip_model()->ActivateTabAt(0, false);
   ASSERT_EQ(0, browser()->tab_strip_model()->active_index());
 
-  // Switch back to new tab.
-  browser()->tab_strip_model()->ActivateTabAt(1, false);
-  ASSERT_EQ(1, browser()->tab_strip_model()->active_index());
-
-  // Confirm that new tab got no onthemechange event while switching tabs.
-  active_tab = browser()->tab_strip_model()->GetActiveWebContents();
-  on_theme_changed_calls = 0;
-  ASSERT_TRUE(instant_test_utils::GetIntFromJS(
-      active_tab, "onThemeChangedCalls", &on_theme_changed_calls));
-  EXPECT_EQ(0, on_theme_changed_calls);
-}
-
-// Flaky on all bots. http://crbug.com/335297, http://crbug.com/265971.
-IN_PROC_BROWSER_TEST_F(InstantThemeTest,
-                       DISABLED_SendThemeBackgroundChangedEvent) {
-  ASSERT_NO_FATAL_FAILURE(SetupInstant(browser()));
-
-  // Install a theme.
-  ASSERT_NO_FATAL_FAILURE(InstallThemeAndVerify("theme", "camo theme"));
-  ASSERT_EQ(1, browser()->tab_strip_model()->count());
+  const std::string helper_js = "document.body.style.cssText";
+  TestThemeInfoObserver observer(
+      InstantServiceFactory::GetForProfile(browser()->profile()));
 
   // Open new tab.
-  ui_test_utils::NavigateToURLWithDisposition(
-      browser(), GURL(chrome::kChromeUINewTabURL),
-      WindowOpenDisposition::NEW_FOREGROUND_TAB,
-      ui_test_utils::BROWSER_TEST_WAIT_FOR_TAB |
-          ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION);
-  ASSERT_EQ(2, browser()->tab_strip_model()->count());
-
-  // Make sure the tab did not receive an onthemechange event for the
-  // already-installed theme. (An event *is* sent, but that happens before the
-  // page can register its handler.)
   content::WebContents* active_tab =
-      browser()->tab_strip_model()->GetActiveWebContents();
+      local_ntp_test_utils::OpenNewTab(browser(), GURL("about:blank"));
+  local_ntp_test_utils::NavigateToNTPAndWaitUntilLoaded(browser());
+  ASSERT_EQ(2, browser()->tab_strip_model()->count());
   ASSERT_EQ(1, browser()->tab_strip_model()->active_index());
-  int on_theme_changed_calls = 0;
-  ASSERT_TRUE(instant_test_utils::GetIntFromJS(
-      active_tab, "onThemeChangedCalls", &on_theme_changed_calls));
-  EXPECT_EQ(0, on_theme_changed_calls);
+  observer.WaitForThemeApplied(false);
+
+  // Get the default (no theme) css setting
+  std::string original_css_text = "";
+  EXPECT_TRUE(instant_test_utils::GetStringFromJS(active_tab, helper_js,
+                                                  &original_css_text));
+
+  // Open a new tab and install a theme on the new tab.
+  active_tab = local_ntp_test_utils::OpenNewTab(browser(), GURL("about:blank"));
+  local_ntp_test_utils::NavigateToNTPAndWaitUntilLoaded(browser());
+  ASSERT_EQ(3, browser()->tab_strip_model()->count());
+  ASSERT_EQ(2, browser()->tab_strip_model()->active_index());
+  ASSERT_NO_FATAL_FAILURE(InstallThemeAndVerify("theme", "camo theme"));
+  observer.WaitForThemeApplied(true);
+
+  // Get the current tab's theme CSS setting.
+  std::string css_text = "";
+  EXPECT_TRUE(
+      instant_test_utils::GetStringFromJS(active_tab, helper_js, &css_text));
+
+  // Switch to the previous tab.
+  browser()->tab_strip_model()->ActivateTabAt(1, false);
+  ASSERT_EQ(1, browser()->tab_strip_model()->active_index());
+  observer.WaitForThemeApplied(true);
+
+  // Get the previous tab's theme CSS setting.
+  std::string previous_tab_css_text = "";
+  EXPECT_TRUE(instant_test_utils::GetStringFromJS(active_tab, helper_js,
+                                                  &previous_tab_css_text));
+
+  // The previous tab should also apply the new theme.
+  EXPECT_NE(original_css_text, css_text);
+  EXPECT_EQ(previous_tab_css_text, css_text);
+}
+
+IN_PROC_BROWSER_TEST_F(InstantThemeTest, ThemeAppliedToNewTab) {
+  // On the existing tab.
+  ASSERT_EQ(1, browser()->tab_strip_model()->count());
+  ASSERT_EQ(0, browser()->tab_strip_model()->active_index());
+
+  const std::string helper_js = "document.body.style.cssText";
+  TestThemeInfoObserver observer(
+      InstantServiceFactory::GetForProfile(browser()->profile()));
+
+  // Open new tab.
+  content::WebContents* active_tab =
+      local_ntp_test_utils::OpenNewTab(browser(), GURL("about:blank"));
+  local_ntp_test_utils::NavigateToNTPAndWaitUntilLoaded(browser());
+  observer.WaitForThemeApplied(false);
+  ASSERT_EQ(2, browser()->tab_strip_model()->count());
+  ASSERT_EQ(1, browser()->tab_strip_model()->active_index());
+
+  // Get the default (no theme) css setting
+  std::string original_css_text = "";
+  EXPECT_TRUE(instant_test_utils::GetStringFromJS(active_tab, helper_js,
+                                                  &original_css_text));
+
+  // Install a theme on this tab.
+  ASSERT_NO_FATAL_FAILURE(InstallThemeAndVerify("theme", "camo theme"));
+  observer.WaitForThemeApplied(true);
+
+  // Get the current tab's theme CSS setting.
+  std::string css_text = "";
+  EXPECT_TRUE(
+      instant_test_utils::GetStringFromJS(active_tab, helper_js, &css_text));
+
+  // Open a new tab.
+  active_tab = local_ntp_test_utils::OpenNewTab(browser(), GURL("about:blank"));
+  local_ntp_test_utils::NavigateToNTPAndWaitUntilLoaded(browser());
+  observer.WaitForThemeApplied(true);
+  ASSERT_EQ(3, browser()->tab_strip_model()->count());
+  ASSERT_EQ(2, browser()->tab_strip_model()->active_index());
+
+  // Get the new tab's theme CSS setting.
+  std::string new_tab_css_text = "";
+  EXPECT_TRUE(instant_test_utils::GetStringFromJS(active_tab, helper_js,
+                                                  &new_tab_css_text));
+
+  // The new tab should change the original theme and also apply the new theme.
+  EXPECT_NE(original_css_text, new_tab_css_text);
+  EXPECT_EQ(css_text, new_tab_css_text);
+}
+
+IN_PROC_BROWSER_TEST_F(InstantThemeTest, ThemeChangedWhenApplyingNewTheme) {
+  // On the existing tab.
+  ASSERT_EQ(1, browser()->tab_strip_model()->count());
+  ASSERT_EQ(0, browser()->tab_strip_model()->active_index());
+
+  const std::string helper_js = "document.body.style.cssText";
+  TestThemeInfoObserver observer(
+      InstantServiceFactory::GetForProfile(browser()->profile()));
+
+  // Open new tab.
+  content::WebContents* active_tab =
+      local_ntp_test_utils::OpenNewTab(browser(), GURL("about:blank"));
+  local_ntp_test_utils::NavigateToNTPAndWaitUntilLoaded(browser());
+  observer.WaitForThemeApplied(false);
+  ASSERT_EQ(2, browser()->tab_strip_model()->count());
+  ASSERT_EQ(1, browser()->tab_strip_model()->active_index());
+
+  // Get the default (no theme) css setting
+  std::string original_css_text = "";
+  EXPECT_TRUE(instant_test_utils::GetStringFromJS(active_tab, helper_js,
+                                                  &original_css_text));
+
+  // install a theme on this tab.
+  ASSERT_NO_FATAL_FAILURE(InstallThemeAndVerify("theme", "camo theme"));
+  observer.WaitForThemeApplied(true);
+
+  // Get the current tab's theme CSS setting.
+  std::string css_text = "";
+  EXPECT_TRUE(
+      instant_test_utils::GetStringFromJS(active_tab, helper_js, &css_text));
 
   // Install a different theme.
   ASSERT_NO_FATAL_FAILURE(InstallThemeAndVerify("theme2", "snowflake theme"));
+  observer.WaitForThemeApplied(true);
 
-  // Confirm that the new tab got notified about the theme changed event.
-  on_theme_changed_calls = 0;
-  ASSERT_TRUE(instant_test_utils::GetIntFromJS(
-      active_tab, "onThemeChangedCalls", &on_theme_changed_calls));
-  EXPECT_EQ(1, on_theme_changed_calls);
-}
+  // Get the current tab's theme CSS setting.
+  std::string new_css_text = "";
+  EXPECT_TRUE(instant_test_utils::GetStringFromJS(active_tab, helper_js,
+                                                  &new_css_text));
+
+  // Confirm that the theme will take effect on the current tab when installing
+  // a new theme.
+  EXPECT_NE(original_css_text, css_text);
+  EXPECT_NE(css_text, new_css_text);
+  EXPECT_NE(original_css_text, new_css_text);
+}
\ No newline at end of file
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
index 7ed89c0a..609e079 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view.cc
@@ -162,11 +162,6 @@
 
 SkColor BrowserNonClientFrameView::GetFrameColor(
     ActiveState active_state) const {
-  extensions::HostedAppBrowserController* hosted_app_controller =
-      browser_view_->browser()->hosted_app_controller();
-  if (hosted_app_controller && hosted_app_controller->GetThemeColor())
-    return *hosted_app_controller->GetThemeColor();
-
   ThemeProperties::OverwritableByUserThemeProperty color_id;
   if (ShouldPaintAsSingleTabMode()) {
     color_id = ThemeProperties::COLOR_TOOLBAR;
@@ -175,10 +170,26 @@
                    ? ThemeProperties::COLOR_FRAME
                    : ThemeProperties::COLOR_FRAME_INACTIVE;
   }
-  return ShouldPaintAsThemed()
-             ? GetThemeProviderForProfile()->GetColor(color_id)
-             : ThemeProperties::GetDefaultColor(color_id,
-                                                browser_view_->IsIncognito());
+
+  // For hosted app windows, if "painting as themed" (which is only true when on
+  // Linux and using the system theme), prefer the system theme color over the
+  // hosted app theme color. The title bar will be painted in the system theme
+  // color (regardless of what we do here), so by returning the system title bar
+  // background color here, we ensure that:
+  // a) The side and bottom borders are painted in the same color as the title
+  // bar background, and
+  // b) The title text is painted in a color that contrasts with the title bar
+  // background.
+  if (ShouldPaintAsThemed())
+    return GetThemeProviderForProfile()->GetColor(color_id);
+
+  extensions::HostedAppBrowserController* hosted_app_controller =
+      browser_view_->browser()->hosted_app_controller();
+  if (hosted_app_controller && hosted_app_controller->GetThemeColor())
+    return *hosted_app_controller->GetThemeColor();
+
+  return ThemeProperties::GetDefaultColor(color_id,
+                                          browser_view_->IsIncognito());
 }
 
 SkColor BrowserNonClientFrameView::GetToolbarTopSeparatorColor() const {
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_browsertest.cc
index 40baf83..6049e41 100644
--- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_browsertest.cc
+++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_browsertest.cc
@@ -5,13 +5,70 @@
 #include "chrome/browser/ui/views/frame/browser_non_client_frame_view.h"
 
 #include "build/build_config.h"
+#include "chrome/browser/extensions/browsertest_util.h"
 #include "chrome/browser/extensions/extension_browsertest.h"
 #include "chrome/browser/themes/theme_properties.h"
+#include "chrome/browser/themes/theme_service.h"
+#include "chrome/browser/themes/theme_service_factory.h"
 #include "chrome/browser/ui/views/frame/browser_view.h"
+#include "chrome/common/chrome_features.h"
+#include "chrome/common/web_application_info.h"
+#include "chrome/test/base/in_process_browser_test.h"
+#include "chrome/test/views/scoped_macviews_browser_mode.h"
+#include "content/public/test/test_navigation_observer.h"
 #include "ui/base/material_design/material_design_controller.h"
 #include "ui/base/theme_provider.h"
 
-using BrowserNonClientFrameViewBrowserTest = extensions::ExtensionBrowserTest;
+class BrowserNonClientFrameViewBrowserTest
+    : public extensions::ExtensionBrowserTest {
+ public:
+  BrowserNonClientFrameViewBrowserTest() = default;
+  ~BrowserNonClientFrameViewBrowserTest() override = default;
+
+  void SetUpOnMainThread() override {
+    ExtensionBrowserTest::SetUpOnMainThread();
+    scoped_feature_list_.InitAndEnableFeature(features::kDesktopPWAWindowing);
+  }
+
+  // Note: A "bookmark app" is a type of hosted app. All of these tests apply
+  // equally to hosted and bookmark apps, but it's easier to install a bookmark
+  // app in a test.
+  void InstallAndLaunchBookmarkApp() {
+    WebApplicationInfo web_app_info;
+    web_app_info.app_url = GetAppURL();
+    web_app_info.scope = GetAppURL().GetWithoutFilename();
+    if (app_theme_color_)
+      web_app_info.theme_color = *app_theme_color_;
+
+    const extensions::Extension* app =
+        extensions::browsertest_util::InstallBookmarkApp(browser()->profile(),
+                                                         web_app_info);
+    content::TestNavigationObserver navigation_observer(GetAppURL());
+    navigation_observer.StartWatchingNewWebContents();
+    Browser* app_browser = extensions::browsertest_util::LaunchAppBrowser(
+        browser()->profile(), app);
+    navigation_observer.WaitForNavigationFinished();
+
+    BrowserView* browser_view =
+        BrowserView::GetBrowserViewForBrowser(app_browser);
+    app_frame_view_ = browser_view->frame()->GetFrameView();
+  }
+
+ protected:
+  base::Optional<SkColor> app_theme_color_ = SK_ColorBLUE;
+  BrowserNonClientFrameView* app_frame_view_ = nullptr;
+
+ private:
+  GURL GetAppURL() { return GURL("https://test.org"); }
+
+  base::test::ScopedFeatureList scoped_feature_list_;
+
+  // Test doesn't work (or make sense) in non-Views Mac. Force it to run in the
+  // Views browser.
+  test::ScopedMacViewsBrowserMode views_mode_{true};
+
+  DISALLOW_COPY_AND_ASSIGN(BrowserNonClientFrameViewBrowserTest);
+};
 
 // Test is Flaky on Windows see crbug.com/600201.
 #if defined(OS_WIN)
@@ -25,7 +82,7 @@
 
 // Tests that the color returned by
 // BrowserNonClientFrameView::GetToolbarTopSeparatorColor() tracks the window
-// actiavtion state.
+// activation state.
 IN_PROC_BROWSER_TEST_F(BrowserNonClientFrameViewBrowserTest,
                        MAYBE_InactiveSeparatorColor) {
   // Refresh does not draw the toolbar top separator.
@@ -39,25 +96,98 @@
   const BrowserNonClientFrameView* frame_view =
       browser_view->frame()->GetFrameView();
   const ui::ThemeProvider* theme_provider = frame_view->GetThemeProvider();
-  const SkColor theme_active_color =
+  const SkColor expected_active_color =
       theme_provider->GetColor(ThemeProperties::COLOR_TOOLBAR_TOP_SEPARATOR);
-  const SkColor theme_inactive_color =
-      theme_provider->GetColor(
-          ThemeProperties::COLOR_TOOLBAR_TOP_SEPARATOR_INACTIVE);
-  EXPECT_NE(theme_active_color, theme_inactive_color);
+  const SkColor expected_inactive_color = theme_provider->GetColor(
+      ThemeProperties::COLOR_TOOLBAR_TOP_SEPARATOR_INACTIVE);
+  EXPECT_NE(expected_active_color, expected_inactive_color);
 
-  // Check that the separator color is the active color when the window is
-  // active.
   browser_view->Activate();
   EXPECT_TRUE(browser_view->IsActive());
-  const SkColor frame_active_color = frame_view->GetToolbarTopSeparatorColor();
-  EXPECT_EQ(theme_active_color, frame_active_color);
+  EXPECT_EQ(expected_active_color, frame_view->GetToolbarTopSeparatorColor());
 
-  // Check that the separator color is the inactive color when the window is
-  // inactive.
   browser_view->Deactivate();
   EXPECT_FALSE(browser_view->IsActive());
-  const SkColor frame_inactive_color =
-      frame_view->GetToolbarTopSeparatorColor();
-  EXPECT_EQ(theme_inactive_color, frame_inactive_color);
+  EXPECT_EQ(expected_inactive_color, frame_view->GetToolbarTopSeparatorColor());
+}
+
+// Tests the frame color for a normal browser window.
+IN_PROC_BROWSER_TEST_F(BrowserNonClientFrameViewBrowserTest,
+                       BrowserFrameColorThemed) {
+  InstallExtension(test_data_dir_.AppendASCII("theme"), 1);
+
+  BrowserView* browser_view = BrowserView::GetBrowserViewForBrowser(browser());
+  const BrowserNonClientFrameView* frame_view =
+      browser_view->frame()->GetFrameView();
+  const ui::ThemeProvider* theme_provider = frame_view->GetThemeProvider();
+  const SkColor expected_active_color =
+      theme_provider->GetColor(ThemeProperties::COLOR_FRAME);
+  const SkColor expected_inactive_color =
+      theme_provider->GetColor(ThemeProperties::COLOR_FRAME_INACTIVE);
+
+  EXPECT_EQ(expected_active_color,
+            frame_view->GetFrameColor(BrowserNonClientFrameView::kActive));
+  EXPECT_EQ(expected_inactive_color,
+            frame_view->GetFrameColor(BrowserNonClientFrameView::kInactive));
+}
+
+// Tests the frame color for a bookmark app when a theme is applied.
+//
+// Disabled because it hits a DCHECK in BrowserView.
+// TODO(mgiuca): Remove this DCHECK, since it seems legitimate.
+// https://crbug.com/879030.
+IN_PROC_BROWSER_TEST_F(BrowserNonClientFrameViewBrowserTest,
+                       DISABLED_BookmarkAppFrameColorCustomTheme) {
+  // The theme color should not affect the window, but the theme must not be the
+  // default GTK theme for Linux so we install one anyway.
+  InstallExtension(test_data_dir_.AppendASCII("theme"), 1);
+  InstallAndLaunchBookmarkApp();
+  // Note: This is checking for the bookmark app's theme color, not the user's
+  // theme color.
+  EXPECT_EQ(*app_theme_color_,
+            app_frame_view_->GetFrameColor(BrowserNonClientFrameView::kActive));
+}
+
+// Tests the frame color for a bookmark app when a theme is applied, with the
+// app itself having no theme color.
+//
+// Disabled because it hits a DCHECK in BrowserView.
+// TODO(mgiuca): Remove this DCHECK, since it seems legitimate.
+// https://crbug.com/879030.
+IN_PROC_BROWSER_TEST_F(BrowserNonClientFrameViewBrowserTest,
+                       DISABLED_BookmarkAppFrameColorCustomThemeNoThemeColor) {
+  InstallExtension(test_data_dir_.AppendASCII("theme"), 1);
+  app_theme_color_.reset();
+  InstallAndLaunchBookmarkApp();
+  // Bookmark apps are not affected by browser themes.
+  EXPECT_EQ(
+      ThemeProperties::GetDefaultColor(ThemeProperties::COLOR_FRAME, false),
+      app_frame_view_->GetFrameColor(BrowserNonClientFrameView::kActive));
+}
+
+// Tests the frame color for a bookmark app when the system theme is applied.
+IN_PROC_BROWSER_TEST_F(BrowserNonClientFrameViewBrowserTest,
+                       BookmarkAppFrameColorSystemTheme) {
+  ThemeService* theme_service =
+      ThemeServiceFactory::GetForProfile(browser()->profile());
+  // Should be using the system theme by default, but this assert was not true
+  // on the bots. Explicitly set.
+  theme_service->UseSystemTheme();
+  ASSERT_TRUE(theme_service->UsingSystemTheme());
+
+  InstallAndLaunchBookmarkApp();
+#if defined(OS_LINUX) && !defined(OS_CHROMEOS)
+  // On Linux, the system theme is the GTK theme and should change the frame
+  // color to the system color (not the app theme color); otherwise the title
+  // and border would clash horribly with the GTK title bar.
+  // (https://crbug.com/878636)
+  const ui::ThemeProvider* theme_provider = app_frame_view_->GetThemeProvider();
+  const SkColor frame_color =
+      theme_provider->GetColor(ThemeProperties::COLOR_FRAME);
+  EXPECT_EQ(frame_color,
+            app_frame_view_->GetFrameColor(BrowserNonClientFrameView::kActive));
+#else
+  EXPECT_EQ(*app_theme_color_,
+            app_frame_view_->GetFrameColor(BrowserNonClientFrameView::kActive));
+#endif
 }
diff --git a/chrome/browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc b/chrome/browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc
index af4b8e4..e02f1d6 100644
--- a/chrome/browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc
+++ b/chrome/browser/ui/views/frame/browser_window_property_manager_browsertest_win.cc
@@ -34,7 +34,6 @@
 #include "chrome/browser/web_applications/components/web_app_shortcut_win.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/extensions/extension_constants.h"
-#include "chrome/installer/util/browser_distribution.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "content/public/test/test_utils.h"
 #include "extensions/common/constants.h"
@@ -70,11 +69,11 @@
   EXPECT_EQ(S_OK, pps->GetValue(PKEY_AppUserModel_RelaunchDisplayNameResource,
                                 prop_var.Receive()));
   EXPECT_EQ(VT_LPWSTR, prop_var.get().vt);
-  EXPECT_EQ(
-      base::FilePath(profiles::internal::GetShortcutFilenameForProfile(
-          expected_profile_name,
-          BrowserDistribution::GetDistribution())).RemoveExtension().value(),
-      prop_var.get().pwszVal);
+  EXPECT_EQ(base::FilePath(profiles::internal::GetShortcutFilenameForProfile(
+                               expected_profile_name))
+                .RemoveExtension()
+                .value(),
+            prop_var.get().pwszVal);
   prop_var.Reset();
 
   // The relaunch command should specify the profile.
diff --git a/chrome/browser/ui/views/frame/opaque_browser_frame_view_linux.cc b/chrome/browser/ui/views/frame/opaque_browser_frame_view_linux.cc
index 3d7b8d4..05b10c0 100644
--- a/chrome/browser/ui/views/frame/opaque_browser_frame_view_linux.cc
+++ b/chrome/browser/ui/views/frame/opaque_browser_frame_view_linux.cc
@@ -31,8 +31,6 @@
 }
 
 bool OpaqueBrowserFrameViewLinux::IsUsingSystemTheme() {
-  // On X11, this does the correct thing. On Windows, UsingSystemTheme() will
-  // return true when using the default blue theme too.
   return theme_service_->UsingSystemTheme();
 }
 
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_helper.cc b/chrome/browser/ui/views/media_router/cast_dialog_helper.cc
new file mode 100644
index 0000000..5a41393
--- /dev/null
+++ b/chrome/browser/ui/views/media_router/cast_dialog_helper.cc
@@ -0,0 +1,29 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/ui/views/media_router/cast_dialog_helper.h"
+
+#include "ui/gfx/geometry/insets.h"
+#include "ui/views/border.h"
+#include "ui/views/controls/throbber.h"
+#include "ui/views/layout/fill_layout.h"
+
+namespace media_router {
+
+std::unique_ptr<views::View> CreateThrobber() {
+  views::Throbber* throbber = new views::Throbber();
+  throbber->Start();
+  auto throbber_container = std::make_unique<views::View>();
+  throbber_container->SetLayoutManager(std::make_unique<views::FillLayout>());
+  // The throbber is smaller than other icons, so the difference must be added
+  // to the border to make their overall sizes match.
+  const int extra_borders =
+      kPrimaryIconSize - throbber->CalculatePreferredSize().height();
+  throbber_container->SetBorder(views::CreateEmptyBorder(
+      gfx::Insets(extra_borders / 2 + kPrimaryIconBorderWidth)));
+  throbber_container->AddChildView(throbber);
+  return throbber_container;
+}
+
+}  // namespace media_router
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_helper.h b/chrome/browser/ui/views/media_router/cast_dialog_helper.h
new file mode 100644
index 0000000..182a5333
--- /dev/null
+++ b/chrome/browser/ui/views/media_router/cast_dialog_helper.h
@@ -0,0 +1,24 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_CAST_DIALOG_HELPER_H_
+#define CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_CAST_DIALOG_HELPER_H_
+
+#include <memory>
+
+#include "ui/views/view.h"
+
+namespace media_router {
+
+// Icon sizes in DIP.
+constexpr int kPrimaryIconSize = 20;
+constexpr int kPrimaryIconBorderWidth = 6;
+
+// Creates a view containing a throbber. The throbber has a border around it so
+// that the view's size is the same with the primary icon with its border.
+std::unique_ptr<views::View> CreateThrobber();
+
+}  // namespace media_router
+
+#endif  // CHROME_BROWSER_UI_VIEWS_MEDIA_ROUTER_CAST_DIALOG_HELPER_H_
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_no_sinks_view.cc b/chrome/browser/ui/views/media_router/cast_dialog_no_sinks_view.cc
index e197260..b0e0974a 100644
--- a/chrome/browser/ui/views/media_router/cast_dialog_no_sinks_view.cc
+++ b/chrome/browser/ui/views/media_router/cast_dialog_no_sinks_view.cc
@@ -13,7 +13,7 @@
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_tabstrip.h"
 #include "chrome/browser/ui/views/hover_button.h"
-#include "chrome/browser/ui/views/media_router/cast_dialog_sink_button.h"
+#include "chrome/browser/ui/views/media_router/cast_dialog_helper.h"
 #include "chrome/common/url_constants.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/vector_icons/vector_icons.h"
@@ -30,18 +30,6 @@
 
 namespace media_router {
 
-namespace {
-
-std::unique_ptr<views::ImageView> CreateTvIcon() {
-  auto icon = std::make_unique<views::ImageView>();
-  // Share the icon size with sink buttons for consistency.
-  icon->SetImage(gfx::CreateVectorIcon(
-      kTvIcon, CastDialogSinkButton::kPrimaryIconSize, gfx::kGoogleGrey500));
-  return icon;
-}
-
-}  // namespace
-
 CastDialogNoSinksView::CastDialogNoSinksView(Browser* browser)
     : browser_(browser), weak_factory_(this) {
   SetLayoutManager(
@@ -81,10 +69,8 @@
 views::View* CastDialogNoSinksView::CreateLookingForSinksView() {
   base::string16 title =
       l10n_util::GetStringUTF16(IDS_MEDIA_ROUTER_STATUS_LOOKING_FOR_DEVICES);
-  auto throbber = std::make_unique<views::Throbber>();
-  throbber->Start();
-  HoverButton* view = new HoverButton(nullptr, CreateTvIcon(), title,
-                                      base::string16(), std::move(throbber));
+  HoverButton* view = new HoverButton(
+      /* button_listener */ nullptr, CreateThrobber(), title, base::string16());
   view->SetEnabled(false);
   return view;
 }
@@ -96,12 +82,14 @@
   views::ImageButton* help_icon_ptr = help_icon.get();
   help_icon->SetImage(
       views::Button::STATE_NORMAL,
-      gfx::CreateVectorIcon(::vector_icons::kHelpOutlineIcon,
-                            CastDialogSinkButton::kPrimaryIconSize,
+      gfx::CreateVectorIcon(::vector_icons::kHelpOutlineIcon, kPrimaryIconSize,
                             gfx::kChromeIconGrey));
   help_icon->SetFocusForPlatform();
-  HoverButton* view = new HoverButton(nullptr, CreateTvIcon(), title,
-                                      base::string16(), std::move(help_icon));
+  help_icon->SetBorder(
+      views::CreateEmptyBorder(gfx::Insets(kPrimaryIconBorderWidth)));
+  HoverButton* view =
+      new HoverButton(/* button_listener */ nullptr, std::move(help_icon),
+                      title, base::string16());
   view->SetEnabled(false);
   // HoverButton disables event handling by its icons, so enable it again.
   help_icon_ptr->set_can_process_events_within_subtree(true);
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc b/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc
index 955c52bb..e9201f6 100644
--- a/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc
+++ b/chrome/browser/ui/views/media_router/cast_dialog_sink_button.cc
@@ -8,6 +8,7 @@
 #include "chrome/app/vector_icons/vector_icons.h"
 #include "chrome/browser/ui/views/chrome_layout_provider.h"
 #include "chrome/browser/ui/views/chrome_typography.h"
+#include "chrome/browser/ui/views/media_router/cast_dialog_helper.h"
 #include "chrome/common/media_router/issue.h"
 #include "chrome/grit/generated_resources.h"
 #include "components/vector_icons/vector_icons.h"
@@ -38,13 +39,11 @@
       : views::LabelButton(button_listener, base::string16()) {
     // TODO(https://crbug.com/877702): Update the icon to match the mocks.
     static const gfx::ImageSkia icon = CreateVectorIcon(
-        kNavigateStopIcon, CastDialogSinkButton::kPrimaryIconSize,
-        gfx::kGoogleBlue500);
+        kNavigateStopIcon, kPrimaryIconSize, gfx::kGoogleBlue500);
     SetImage(views::Button::STATE_NORMAL, icon);
     SetInkDropMode(views::InkDropHostView::InkDropMode::ON);
     set_tag(button_tag);
-    SetBorder(views::CreateEmptyBorder(
-        gfx::Insets(CastDialogSinkButton::kPrimaryIconBorderWidth)));
+    SetBorder(views::CreateEmptyBorder(gfx::Insets(kPrimaryIconBorderWidth)));
     SetEnabled(enabled);
     // Make it possible to navigate to this button by pressing the tab key.
     SetFocusBehavior(FocusBehavior::ALWAYS);
@@ -103,52 +102,37 @@
       break;
   }
   SkColor icon_color = enabled ? gfx::kChromeIconGrey : gfx::kGoogleGrey500;
-  return gfx::CreateVectorIcon(
-      *vector_icon, CastDialogSinkButton::kPrimaryIconSize, icon_color);
+  return gfx::CreateVectorIcon(*vector_icon, kPrimaryIconSize, icon_color);
 }
 
 gfx::ImageSkia CreateDisabledSinkIcon(SinkIconType icon_type) {
   return CreateSinkIcon(icon_type, false);
 }
 
-std::unique_ptr<views::View> CreateThrobber() {
-  views::Throbber* throbber = new views::Throbber();
-  throbber->Start();
-  auto throbber_container = std::make_unique<views::View>();
-  throbber_container->SetLayoutManager(std::make_unique<views::FillLayout>());
-  // The throbber is smaller than other icons, so the difference must be added
-  // to the border to make their overall sizes match.
-  const int extra_borders = CastDialogSinkButton::kPrimaryIconSize -
-                            throbber->CalculatePreferredSize().height();
-  throbber_container->SetBorder(views::CreateEmptyBorder(gfx::Insets(
-      extra_borders / 2 + CastDialogSinkButton::kPrimaryIconBorderWidth)));
-  throbber_container->AddChildView(throbber);
-  return throbber_container;
-}
-
 std::unique_ptr<views::View> CreatePrimaryIconForSink(
     views::ButtonListener* button_listener,
     const UIMediaSink& sink,
     int button_tag) {
-  if (sink.issue) {
-    auto icon_view = std::make_unique<views::ImageView>();
-    icon_view->SetImage(CreateVectorIcon(::vector_icons::kInfoOutlineIcon,
-                                         CastDialogSinkButton::kPrimaryIconSize,
-                                         gfx::kChromeIconGrey));
-    icon_view->SetBorder(views::CreateEmptyBorder(
-        gfx::Insets(CastDialogSinkButton::kPrimaryIconBorderWidth)));
-    return icon_view;
-  } else if (sink.state == UIMediaSinkState::CONNECTED ||
-             sink.state == UIMediaSinkState::DISCONNECTING) {
+  // The stop button has the highest priority, and the issue icon comes second.
+  if (sink.state == UIMediaSinkState::CONNECTED ||
+      sink.state == UIMediaSinkState::DISCONNECTING) {
     return std::make_unique<StopButton>(
         button_listener, button_tag, sink.state == UIMediaSinkState::CONNECTED);
+  } else if (sink.issue) {
+    auto icon_view = std::make_unique<views::ImageView>();
+    icon_view->SetImage(CreateVectorIcon(::vector_icons::kInfoOutlineIcon,
+                                         kPrimaryIconSize,
+                                         gfx::kChromeIconGrey));
+    icon_view->SetBorder(
+        views::CreateEmptyBorder(gfx::Insets(kPrimaryIconBorderWidth)));
+    return icon_view;
   } else if (sink.state == UIMediaSinkState::CONNECTING) {
     return CreateThrobber();
   }
   auto icon_view = std::make_unique<views::ImageView>();
   icon_view->SetImage(CreateSinkIcon(sink.icon_type));
-  icon_view->SetBorder(views::CreateEmptyBorder(
-      gfx::Insets(CastDialogSinkButton::kPrimaryIconBorderWidth)));
+  icon_view->SetBorder(
+      views::CreateEmptyBorder(gfx::Insets(kPrimaryIconBorderWidth)));
   return icon_view;
 }
 
@@ -169,11 +153,6 @@
 
 }  // namespace
 
-// static
-int CastDialogSinkButton::kPrimaryIconSize = 20;
-int CastDialogSinkButton::kPrimaryIconBorderWidth = 6;
-int CastDialogSinkButton::kSecondaryIconSize = 16;
-
 CastDialogSinkButton::CastDialogSinkButton(
     views::ButtonListener* button_listener,
     const UIMediaSink& sink,
diff --git a/chrome/browser/ui/views/media_router/cast_dialog_sink_button.h b/chrome/browser/ui/views/media_router/cast_dialog_sink_button.h
index ee383327..dc443eda 100644
--- a/chrome/browser/ui/views/media_router/cast_dialog_sink_button.h
+++ b/chrome/browser/ui/views/media_router/cast_dialog_sink_button.h
@@ -18,12 +18,6 @@
 // hovered.
 class CastDialogSinkButton : public HoverButton {
  public:
-  // Icon sizes in DIP. These values are also used by the "no devices" view for
-  // consistency.
-  static int kPrimaryIconSize;
-  static int kPrimaryIconBorderWidth;
-  static int kSecondaryIconSize;
-
   CastDialogSinkButton(views::ButtonListener* button_listener,
                        const UIMediaSink& sink,
                        int button_tag);
diff --git a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
index fb01ca7..378efe25 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_result_view.cc
@@ -335,8 +335,11 @@
   // The positional info is provided via
   // ax::mojom::IntAttribute::kPosInSet/SET_SIZE and providing it via text as
   // well would result in duplicate announcements.
-  node_data->SetName(
-      AutocompleteMatchType::ToAccessibilityLabel(match_, match_.contents));
+  // Pass false for is_tab_switch_button_focused, because the button will
+  // receive its own label in the case that a screen reader is listening to
+  // selection events on items rather than announcements or value change events.
+  node_data->SetName(AutocompleteMatchType::ToAccessibilityLabel(
+      match_, match_.contents, false));
 
   node_data->role = ax::mojom::Role::kListBoxOption;
   node_data->AddIntAttribute(ax::mojom::IntAttribute::kPosInSet,
diff --git a/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.cc b/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.cc
index 9d937c5..cfd2708b 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.cc
@@ -12,11 +12,13 @@
 #include "chrome/browser/ui/views/omnibox/omnibox_result_view.h"
 #include "components/omnibox/browser/vector_icons.h"
 #include "components/strings/grit/components_strings.h"
+#include "ui/accessibility/ax_node_data.h"
 #include "ui/base/l10n/l10n_util.h"
 #include "ui/gfx/animation/slide_animation.h"
 #include "ui/gfx/color_palette.h"
 #include "ui/gfx/color_utils.h"
 #include "ui/gfx/paint_vector_icon.h"
+#include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/animation/ink_drop_mask.h"
 
 bool OmniboxTabSwitchButton::calculated_widths_ = false;
@@ -144,7 +146,16 @@
 }
 
 void OmniboxTabSwitchButton::ProvideFocusHint() {
-  NotifyAccessibilityEvent(ax::mojom::Event::kHover, true);
+  NotifyAccessibilityEvent(ax::mojom::Event::kSelection, true);
+}
+
+void OmniboxTabSwitchButton::GetAccessibleNodeData(ui::AXNodeData* node_data) {
+  node_data->SetName(l10n_util::GetStringUTF8(IDS_ACC_TAB_SWITCH_BUTTON));
+  // Although this appears visually as a button, expose as a list box option so
+  // that it matches the other options within its list box container.
+  node_data->role = ax::mojom::Role::kListBoxOption;
+  node_data->AddBoolAttribute(ax::mojom::BoolAttribute::kSelected,
+                              IsSelected());
 }
 
 bool OmniboxTabSwitchButton::IsSelected() const {
diff --git a/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.h b/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.h
index 4228ef7..23e45c90 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.h
+++ b/chrome/browser/ui/views/omnibox/omnibox_tab_switch_button.h
@@ -42,6 +42,7 @@
 
   // Called to indicate button has been focused.
   void ProvideFocusHint();
+  void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
 
  private:
   // Consults the parent views to see if the button is selected.
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index 47eb60d..cb43ab9 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -578,10 +578,13 @@
     saved_temporary_selection_ = GetSelectedRange();
 
   // Get friendly accessibility label.
+  bool is_tab_switch_button_focused =
+      model()->popup_model()->selected_line_state() ==
+      OmniboxPopupModel::TAB_SWITCH;
   friendly_suggestion_text_ = AutocompleteMatchType::ToAccessibilityLabel(
       match, display_text, model()->popup_model()->selected_line(),
-      model()->result().size(), &friendly_suggestion_text_prefix_length_);
-
+      model()->result().size(), is_tab_switch_button_focused,
+      &friendly_suggestion_text_prefix_length_);
   SetWindowTextAndCaretPos(display_text, display_text.length(), false,
                            notify_text_changed);
 #if defined(OS_MACOSX)
diff --git a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_handler.cc b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_handler.cc
index c550b13..82c5ca0 100644
--- a/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_handler.cc
+++ b/chrome/browser/ui/webui/chromeos/assistant_optin/assistant_optin_handler.cc
@@ -143,12 +143,18 @@
   ui_audit_key_ = activity_control_ui.ui_audit_key();
 
   // Process activity control data.
-  if (!activity_control_ui.setting_zippy().size()) {
+  bool skip_activity_control = !activity_control_ui.setting_zippy().size();
+  if (skip_activity_control) {
     // No need to consent. Move to the next screen.
     activity_control_needed_ = false;
     PrefService* prefs = Profile::FromWebUI(web_ui())->GetPrefs();
-    prefs->SetBoolean(arc::prefs::kVoiceInteractionActivityControlAccepted,
-                      true);
+    prefs->SetBoolean(
+        arc::prefs::kVoiceInteractionActivityControlAccepted,
+        (settings_ui.consent_flow_ui().consent_status() ==
+             assistant::ConsentFlowUi_ConsentStatus_ALREADY_CONSENTED ||
+         settings_ui.consent_flow_ui().consent_status() ==
+             assistant::ConsentFlowUi_ConsentStatus_ASK_FOR_CONSENT));
+    // Skip activity control and users will be in opted out mode.
     ShowNextScreen();
   } else {
     AddSettingZippy("settings",
@@ -156,14 +162,36 @@
   }
 
   // Process third party disclosure data.
-  AddSettingZippy("disclosure", CreateDisclosureData(
-                                    third_party_disclosure_ui.disclosures()));
+  bool skip_third_party_disclosure =
+      skip_activity_control && !third_party_disclosure_ui.disclosures().size();
+  if (third_party_disclosure_ui.disclosures().size()) {
+    AddSettingZippy("disclosure", CreateDisclosureData(
+                                      third_party_disclosure_ui.disclosures()));
+  } else if (skip_third_party_disclosure) {
+    ShowNextScreen();
+  } else {
+    // TODO(llin): Show an error message and log it properly.
+    LOG(ERROR) << "Missing third Party disclosure data.";
+    return;
+  }
 
   // Process get more data.
   email_optin_needed_ = settings_ui.has_email_opt_in_ui() &&
                         settings_ui.email_opt_in_ui().has_title();
-  AddSettingZippy("get-more", CreateGetMoreData(email_optin_needed_,
-                                                settings_ui.email_opt_in_ui()));
+  auto get_more_data =
+      CreateGetMoreData(email_optin_needed_, settings_ui.email_opt_in_ui());
+
+  bool skip_get_more =
+      skip_third_party_disclosure && !get_more_data.GetList().size();
+  if (get_more_data.GetList().size()) {
+    AddSettingZippy("get-more", get_more_data);
+  } else if (skip_get_more) {
+    ShowNextScreen();
+  } else {
+    // TODO(llin): Show an error message and log it properly.
+    LOG(ERROR) << "Missing get more data.";
+    return;
+  }
 
   // Pass string constants dictionary.
   ReloadContent(GetSettingsUiStrings(settings_ui, activity_control_needed_));
diff --git a/chrome/browser/ui/webui/chromeos/multidevice_setup/multidevice_setup_dialog.cc b/chrome/browser/ui/webui/chromeos/multidevice_setup/multidevice_setup_dialog.cc
index f3e6f52..b8330ee0 100644
--- a/chrome/browser/ui/webui/chromeos/multidevice_setup/multidevice_setup_dialog.cc
+++ b/chrome/browser/ui/webui/chromeos/multidevice_setup/multidevice_setup_dialog.cc
@@ -7,6 +7,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/webui/chromeos/multidevice_setup/multidevice_setup_handler.h"
+#include "chrome/common/url_constants.h"
 #include "chrome/common/webui_url_constants.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/grit/multidevice_setup_resources.h"
@@ -25,9 +26,8 @@
 
 namespace {
 
-// TODO(khorimoto): Replace with actual help center URL when available.
+// TODO(khorimoto): Localize footnote marker if necessary.
 const char kFootnoteMarker[] = "*";
-const char kSetupLearnMoreLink[] = "https://multidevice-learn-more.com";
 
 constexpr int kDialogHeightPx = 640;
 constexpr int kDialogWidthPx = 768;
@@ -77,7 +77,7 @@
       l10n_util::GetStringFUTF16(
           IDS_MULTIDEVICE_SETUP_START_SETUP_PAGE_MESSAGE,
           base::ASCIIToUTF16(kFootnoteMarker),
-          base::ASCIIToUTF16(kSetupLearnMoreLink)));
+          base::ASCIIToUTF16(chrome::kMultiDeviceLearnMoreURL)));
   html_source->AddString(
       "startSetupPageFootnote",
       l10n_util::GetStringFUTF16(
diff --git a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
index 59bc047..13ef668 100644
--- a/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
+++ b/chrome/browser/ui/webui/settings/md_settings_localized_strings_provider.cc
@@ -1777,12 +1777,13 @@
       l10n_util::GetStringFUTF8(IDS_SETTINGS_PASSPHRASE_EXPLANATION_TEXT,
                                 base::ASCIIToUTF16(sync_dashboard_url)));
   html_source->AddString(
-      "passphraseResetHint",
-      l10n_util::GetStringFUTF8(
-          unified_consent::IsUnifiedConsentFeatureEnabled()
-              ? IDS_SETTINGS_PASSPHRASE_RESET_HINT_UNIFIED_CONSENT
-              : IDS_SETTINGS_PASSPHRASE_RESET_HINT,
-          base::ASCIIToUTF16(sync_dashboard_url)));
+      "passphraseResetHintEncryption",
+      l10n_util::GetStringFUTF8(IDS_SETTINGS_PASSPHRASE_RESET_HINT_ENCRYPTION,
+                                base::ASCIIToUTF16(sync_dashboard_url)));
+  html_source->AddString(
+      "passphraseResetHintToggle",
+      l10n_util::GetStringFUTF8(IDS_SETTINGS_PASSPHRASE_RESET_HINT_TOGGLE,
+                                base::ASCIIToUTF16(sync_dashboard_url)));
   html_source->AddString(
       "passphraseRecover",
       l10n_util::GetStringFUTF8(IDS_SETTINGS_PASSPHRASE_RECOVER,
diff --git a/chrome/browser/unified_consent/chrome_unified_consent_service_client.cc b/chrome/browser/unified_consent/chrome_unified_consent_service_client.cc
index 2aef414e..6e60b19 100644
--- a/chrome/browser/unified_consent/chrome_unified_consent_service_client.cc
+++ b/chrome/browser/unified_consent/chrome_unified_consent_service_client.cc
@@ -4,6 +4,7 @@
 
 #include "chrome/browser/unified_consent/chrome_unified_consent_service_client.h"
 
+#include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/metrics/chrome_metrics_service_accessor.h"
 #include "chrome/browser/metrics/metrics_reporting_state.h"
@@ -14,6 +15,10 @@
 #include "components/safe_browsing/common/safe_browsing_prefs.h"
 #include "components/spellcheck/browser/pref_names.h"
 
+#if defined(OS_ANDROID)
+#include "chrome/browser/android/metrics/uma_utils.h"
+#endif
+
 ChromeUnifiedConsentServiceClient::ChromeUnifiedConsentServiceClient(
     PrefService* pref_service)
     : pref_service_(pref_service) {
@@ -83,7 +88,12 @@
       pref_service_->SetBoolean(prefs::kAlternateErrorPagesEnabled, enabled);
       break;
     case Service::kMetricsReporting:
+#if defined(OS_ANDROID)
+      // TODO(https://crbug.com/880936): Move inside ChangeMetricsReportingState
+      chrome::android::SetUsageAndCrashReporting(enabled);
+#else
       ChangeMetricsReportingState(enabled);
+#endif
       break;
     case Service::kNetworkPrediction:
       pref_service_->SetInteger(
diff --git a/chrome/browser/upgrade_detector/upgrade_detector_impl.cc b/chrome/browser/upgrade_detector/upgrade_detector_impl.cc
index c76bd0f..67bbade 100644
--- a/chrome/browser/upgrade_detector/upgrade_detector_impl.cc
+++ b/chrome/browser/upgrade_detector/upgrade_detector_impl.cc
@@ -24,6 +24,7 @@
 #include "base/task/task_traits.h"
 #include "base/task_runner.h"
 #include "base/task_runner_util.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/time/default_tick_clock.h"
 #include "base/time/time.h"
@@ -106,7 +107,7 @@
 // Gets the currently installed version. On Windows, if |critical_update| is not
 // NULL, also retrieves the critical update version info if available.
 base::Version GetCurrentlyInstalledVersionImpl(base::Version* critical_update) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
 
   base::Version installed_version;
 #if defined(OS_WIN)
diff --git a/chrome/browser/web_applications/components/web_app_shortcut_win.cc b/chrome/browser/web_applications/components/web_app_shortcut_win.cc
index d5c0276..58d1668 100644
--- a/chrome/browser/web_applications/components/web_app_shortcut_win.cc
+++ b/chrome/browser/web_applications/components/web_app_shortcut_win.cc
@@ -26,7 +26,6 @@
 #include "chrome/browser/shell_integration.h"
 #include "chrome/browser/shell_integration_win.h"
 #include "chrome/common/chrome_switches.h"
-#include "chrome/installer/util/browser_distribution.h"
 #include "chrome/installer/util/shell_util.h"
 #include "chrome/installer/util/util_constants.h"
 #include "content/public/browser/browser_thread.h"
@@ -488,8 +487,7 @@
   base::FilePath chrome_apps_dir;
   if (ShellUtil::GetShortcutPath(
           ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR,
-          BrowserDistribution::GetDistribution(), ShellUtil::CURRENT_USER,
-          &chrome_apps_dir)) {
+          ShellUtil::CURRENT_USER, &chrome_apps_dir)) {
     if (base::IsDirectoryEmpty(chrome_apps_dir))
       base::DeleteFile(chrome_apps_dir, false);
   }
@@ -504,8 +502,7 @@
   base::FilePath chrome_apps_dir;
   if (ShellUtil::GetShortcutPath(
           ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR,
-          BrowserDistribution::GetDistribution(), ShellUtil::CURRENT_USER,
-          &chrome_apps_dir)) {
+          ShellUtil::CURRENT_USER, &chrome_apps_dir)) {
     if (base::IsDirectoryEmpty(chrome_apps_dir))
       base::DeleteFile(chrome_apps_dir, false);
   }
@@ -530,12 +527,11 @@
            base::win::CanPinShortcutToTaskbar(),
        ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH}};
 
-  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
   // Populate shortcut_paths.
   for (size_t i = 0; i < base::size(locations); ++i) {
     if (locations[i].use_this_location) {
       base::FilePath path;
-      if (!ShellUtil::GetShortcutPath(locations[i].location_id, dist,
+      if (!ShellUtil::GetShortcutPath(locations[i].location_id,
                                       ShellUtil::CURRENT_USER, &path)) {
         NOTREACHED();
         continue;
diff --git a/chrome/chrome_cleaner/BUILD.gn b/chrome/chrome_cleaner/BUILD.gn
index 84cca93..8c1c399 100644
--- a/chrome/chrome_cleaner/BUILD.gn
+++ b/chrome/chrome_cleaner/BUILD.gn
@@ -43,6 +43,7 @@
     "//chrome/chrome_cleaner/strings:unittest_sources",
     "//chrome/chrome_cleaner/test:unittest_sources",
     "//chrome/chrome_cleaner/ui:unittest_sources",
+    "//chrome/chrome_cleaner/zip_archiver:unittest_sources",
   ]
 }
 
diff --git a/chrome/chrome_cleaner/crash/crashpad_crash_client.cc b/chrome/chrome_cleaner/crash/crashpad_crash_client.cc
index 9fc93170..58658f9 100644
--- a/chrome/chrome_cleaner/crash/crashpad_crash_client.cc
+++ b/chrome/chrome_cleaner/crash/crashpad_crash_client.cc
@@ -198,6 +198,9 @@
     case SandboxType::kJsonParser:
       SetCrashKey(kProcessType, "json_parser");
       break;
+    case SandboxType::kZipArchiver:
+      SetCrashKey(kProcessType, "zip_archiver");
+      break;
     default:
       NOTREACHED();
   }
diff --git a/chrome/chrome_cleaner/interfaces/BUILD.gn b/chrome/chrome_cleaner/interfaces/BUILD.gn
index 370ed2a..be473325 100644
--- a/chrome/chrome_cleaner/interfaces/BUILD.gn
+++ b/chrome/chrome_cleaner/interfaces/BUILD.gn
@@ -40,6 +40,12 @@
   ]
 }
 
+chrome_cleaner_mojom("zip_archiver_interface") {
+  sources = [
+    "zip_archiver.mojom",
+  ]
+}
+
 chrome_cleaner_mojom("engine_sandbox_test_interface") {
   testonly = true
 
diff --git a/chrome/chrome_cleaner/interfaces/zip_archiver.mojom b/chrome/chrome_cleaner/interfaces/zip_archiver.mojom
new file mode 100644
index 0000000..dbe5f67
--- /dev/null
+++ b/chrome/chrome_cleaner/interfaces/zip_archiver.mojom
@@ -0,0 +1,30 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+module chrome_cleaner.mojom;
+
+// Represent result codes from the zip archiver.
+enum ZipArchiverResultCode {
+  kSuccess = 0,
+  kErrorInvalidParameter = 1,
+  // Any error on file operations.
+  kErrorIO = 2,
+  kErrorMinizipInternal = 3,
+  kErrorCannotOpenSourceFile = 4,
+  kErrorCannotCreateZipFile = 5,
+  kZipFileExists = 6,
+  kIgnoredSourceFile = 7,
+};
+
+interface ZipArchiver {
+  // Passes |src_file_handle| which is open for reading and |zip_file_handle|
+  // which is open read/write from the high-privilege sandbox broker process to
+  // a locked down sandbox target process. The implementation will add the
+  // contents of the source file to the zip file, using the name
+  // |filename_in_zip| in the zip index, and encrypting the file with
+  // |password|.
+  Archive(handle src_file_handle, handle zip_file_handle,
+          string filename_in_zip, string password)
+    => (ZipArchiverResultCode result_code);
+};
diff --git a/chrome/chrome_cleaner/logging/proto/shared_data.proto b/chrome/chrome_cleaner/logging/proto/shared_data.proto
index 41c4e5d..3e010fb1 100644
--- a/chrome/chrome_cleaner/logging/proto/shared_data.proto
+++ b/chrome/chrome_cleaner/logging/proto/shared_data.proto
@@ -246,6 +246,7 @@
     DEPRECATED_SIGNATURE_MATCHER_SANDBOX = 2;
     ESET_SANDBOX = 3;
     JSON_PARSER_SANDBOX = 4;
+    ZIP_ARCHIVER_SANDBOX = 5;
   }
   optional Process process = 1;
 
diff --git a/chrome/chrome_cleaner/logging/utils.cc b/chrome/chrome_cleaner/logging/utils.cc
index 0c0c238..4931802 100644
--- a/chrome/chrome_cleaner/logging/utils.cc
+++ b/chrome/chrome_cleaner/logging/utils.cc
@@ -253,6 +253,9 @@
     case SandboxType::kJsonParser:
       process_info.set_process(ProcessInformation::JSON_PARSER_SANDBOX);
       break;
+    case SandboxType::kZipArchiver:
+      process_info.set_process(ProcessInformation::ZIP_ARCHIVER_SANDBOX);
+      break;
     default:
       NOTREACHED() << "Unknown sandbox type " << static_cast<int>(process_type);
   }
diff --git a/chrome/chrome_cleaner/settings/settings_types.h b/chrome/chrome_cleaner/settings/settings_types.h
index 671dee9..6789d79 100644
--- a/chrome/chrome_cleaner/settings/settings_types.h
+++ b/chrome/chrome_cleaner/settings/settings_types.h
@@ -15,6 +15,7 @@
   kTest,
   kEset,
   kJsonParser,
+  kZipArchiver,
   kNumValues,
 };
 
diff --git a/chrome/chrome_cleaner/zip_archiver/BUILD.gn b/chrome/chrome_cleaner/zip_archiver/BUILD.gn
new file mode 100644
index 0000000..fce6906
--- /dev/null
+++ b/chrome/chrome_cleaner/zip_archiver/BUILD.gn
@@ -0,0 +1,58 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+static_library("common") {
+  sources = [
+    "sandboxed_zip_archiver.cc",
+    "sandboxed_zip_archiver.h",
+  ]
+
+  deps = [
+    "//chrome/chrome_cleaner/interfaces:zip_archiver_interface",
+    "//chrome/chrome_cleaner/ipc:mojo_task_runner",
+    "//chrome/chrome_cleaner/os:common_os",
+    "//chrome/chrome_cleaner/zip_archiver/broker:common",
+    "//mojo/public/cpp/system:system",
+  ]
+}
+
+source_set("test_support") {
+  testonly = true
+
+  sources = [
+    "test_zip_archiver_util.cc",
+    "test_zip_archiver_util.h",
+  ]
+
+  deps = [
+    "//base:base",
+    "//testing/gtest",
+    "//third_party/zlib:minizip",
+  ]
+}
+
+source_set("unittest_sources") {
+  testonly = true
+
+  sources = [
+    "sandboxed_zip_archiver_unittest.cc",
+  ]
+
+  deps = [
+    "//base/test:test_support",
+    "//chrome/chrome_cleaner/interfaces:zip_archiver_interface",
+    "//chrome/chrome_cleaner/ipc:mojo_task_runner",
+    "//chrome/chrome_cleaner/os:common_os",
+    "//chrome/chrome_cleaner/zip_archiver:common",
+    "//chrome/chrome_cleaner/zip_archiver:test_support",
+    "//chrome/chrome_cleaner/zip_archiver/broker:common",
+    "//chrome/chrome_cleaner/zip_archiver/target:common",
+    "//sandbox/win:sandbox",
+    "//testing/gtest",
+
+    # Tests from subdirs.
+    "//chrome/chrome_cleaner/zip_archiver/broker:unittest_sources",
+    "//chrome/chrome_cleaner/zip_archiver/target:unittest_sources",
+  ]
+}
diff --git a/chrome/chrome_cleaner/zip_archiver/DEPS b/chrome/chrome_cleaner/zip_archiver/DEPS
new file mode 100644
index 0000000..66946866
--- /dev/null
+++ b/chrome/chrome_cleaner/zip_archiver/DEPS
@@ -0,0 +1,4 @@
+include_rules = [
+  "+third_party/zlib",
+]
+
diff --git a/chrome/chrome_cleaner/zip_archiver/broker/BUILD.gn b/chrome/chrome_cleaner/zip_archiver/broker/BUILD.gn
new file mode 100644
index 0000000..bf41a66
--- /dev/null
+++ b/chrome/chrome_cleaner/zip_archiver/broker/BUILD.gn
@@ -0,0 +1,41 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+static_library("common") {
+  sources = [
+    "sandbox_setup.cc",
+    "sandbox_setup.h",
+  ]
+
+  deps = [
+    "//base:base",
+    "//chrome/chrome_cleaner/constants:common_strings",
+    "//chrome/chrome_cleaner/interfaces:zip_archiver_interface",
+    "//chrome/chrome_cleaner/ipc:mojo_task_runner",
+    "//chrome/chrome_cleaner/ipc:sandbox",
+    "//components/chrome_cleaner/public/constants:constants",
+    "//mojo/public/cpp/system:system",
+    "//sandbox/win:sandbox",
+  ]
+}
+
+source_set("unittest_sources") {
+  testonly = true
+
+  sources = [
+    "sandbox_setup_unittest.cc",
+  ]
+
+  deps = [
+    ":common",
+    "//base:base",
+    "//base/test:test_support",
+    "//chrome/chrome_cleaner/interfaces:zip_archiver_interface",
+    "//chrome/chrome_cleaner/zip_archiver:test_support",
+    "//chrome/chrome_cleaner/zip_archiver/target:common",
+    "//mojo/public/cpp/system:system",
+    "//sandbox/win:sandbox",
+    "//testing/gtest",
+  ]
+}
diff --git a/chrome/chrome_cleaner/zip_archiver/broker/sandbox_setup.cc b/chrome/chrome_cleaner/zip_archiver/broker/sandbox_setup.cc
new file mode 100644
index 0000000..4d25406
--- /dev/null
+++ b/chrome/chrome_cleaner/zip_archiver/broker/sandbox_setup.cc
@@ -0,0 +1,63 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/chrome_cleaner/zip_archiver/broker/sandbox_setup.h"
+
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "mojo/public/cpp/system/message_pipe.h"
+
+namespace chrome_cleaner {
+
+namespace {
+
+void BindZipArchiverPtr(mojom::ZipArchiverPtr* zip_archiver_ptr,
+                        mojo::ScopedMessagePipeHandle pipe_handle,
+                        base::OnceClosure connection_error_handler) {
+  DCHECK(zip_archiver_ptr);
+
+  zip_archiver_ptr->Bind(mojom::ZipArchiverPtrInfo(std::move(pipe_handle), 0));
+  zip_archiver_ptr->set_connection_error_handler(
+      std::move(connection_error_handler));
+}
+
+}  // namespace
+
+ZipArchiverSandboxSetupHooks::ZipArchiverSandboxSetupHooks(
+    scoped_refptr<MojoTaskRunner> mojo_task_runner,
+    base::OnceClosure connection_error_handler)
+    : mojo_task_runner_(mojo_task_runner),
+      connection_error_handler_(std::move(connection_error_handler)),
+      // Manually use |new| here because |make_unique| doesn't work with
+      // custom deleter.
+      zip_archiver_ptr_(new mojom::ZipArchiverPtr(),
+                        base::OnTaskRunnerDeleter(mojo_task_runner_)) {}
+
+ZipArchiverSandboxSetupHooks::~ZipArchiverSandboxSetupHooks() = default;
+
+ResultCode ZipArchiverSandboxSetupHooks::UpdateSandboxPolicy(
+    sandbox::TargetPolicy* policy,
+    base::CommandLine* command_line) {
+  DCHECK(policy);
+  DCHECK(command_line);
+
+  // Unretained pointer of |zip_archiver_ptr_| is safe because its deleter is
+  // run on the same task runner. So it won't be deleted before this task.
+  mojo_task_runner_->PostTask(
+      FROM_HERE, base::BindOnce(BindZipArchiverPtr,
+                                base::Unretained(zip_archiver_ptr_.get()),
+                                SetupSandboxMessagePipe(policy, command_line),
+                                std::move(connection_error_handler_)));
+
+  return RESULT_CODE_SUCCESS;
+}
+
+UniqueZipArchiverPtr ZipArchiverSandboxSetupHooks::TakeZipArchiverPtr() {
+  return std::move(zip_archiver_ptr_);
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/zip_archiver/broker/sandbox_setup.h b/chrome/chrome_cleaner/zip_archiver/broker/sandbox_setup.h
new file mode 100644
index 0000000..8be8e54
--- /dev/null
+++ b/chrome/chrome_cleaner/zip_archiver/broker/sandbox_setup.h
@@ -0,0 +1,47 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_CHROME_CLEANER_ZIP_ARCHIVER_BROKER_SANDBOX_SETUP_H_
+#define CHROME_CHROME_CLEANER_ZIP_ARCHIVER_BROKER_SANDBOX_SETUP_H_
+
+#include <memory>
+
+#include "base/command_line.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/sequenced_task_runner.h"
+#include "chrome/chrome_cleaner/interfaces/zip_archiver.mojom.h"
+#include "chrome/chrome_cleaner/ipc/mojo_sandbox_hooks.h"
+#include "chrome/chrome_cleaner/ipc/mojo_task_runner.h"
+#include "components/chrome_cleaner/public/constants/result_codes.h"
+#include "sandbox/win/src/sandbox_policy.h"
+
+namespace chrome_cleaner {
+
+using UniqueZipArchiverPtr =
+    std::unique_ptr<mojom::ZipArchiverPtr, base::OnTaskRunnerDeleter>;
+
+class ZipArchiverSandboxSetupHooks : public MojoSandboxSetupHooks {
+ public:
+  ZipArchiverSandboxSetupHooks(scoped_refptr<MojoTaskRunner> mojo_task_runner,
+                               base::OnceClosure connection_error_handler);
+  ~ZipArchiverSandboxSetupHooks() override;
+
+  // SandboxSetupHooks
+
+  ResultCode UpdateSandboxPolicy(sandbox::TargetPolicy* policy,
+                                 base::CommandLine* command_line) override;
+
+  UniqueZipArchiverPtr TakeZipArchiverPtr();
+
+ private:
+  scoped_refptr<MojoTaskRunner> mojo_task_runner_;
+  base::OnceClosure connection_error_handler_;
+  UniqueZipArchiverPtr zip_archiver_ptr_;
+
+  DISALLOW_COPY_AND_ASSIGN(ZipArchiverSandboxSetupHooks);
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_ZIP_ARCHIVER_BROKER_SANDBOX_SETUP_H_
diff --git a/chrome/chrome_cleaner/zip_archiver/broker/sandbox_setup_unittest.cc b/chrome/chrome_cleaner/zip_archiver/broker/sandbox_setup_unittest.cc
new file mode 100644
index 0000000..ae6ff72
--- /dev/null
+++ b/chrome/chrome_cleaner/zip_archiver/broker/sandbox_setup_unittest.cc
@@ -0,0 +1,134 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+#include <utility>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/sequenced_task_runner.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/win/scoped_handle.h"
+#include "chrome/chrome_cleaner/interfaces/zip_archiver.mojom.h"
+#include "chrome/chrome_cleaner/zip_archiver/broker/sandbox_setup.h"
+#include "chrome/chrome_cleaner/zip_archiver/target/sandbox_setup.h"
+#include "chrome/chrome_cleaner/zip_archiver/test_zip_archiver_util.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace chrome_cleaner {
+
+namespace {
+
+using mojom::ZipArchiverResultCode;
+
+const char kTestFilenameInZip[] = "a.txt";
+const char kTestPassword[] = "1234";
+
+class ZipArchiverSandboxSetupTest : public base::MultiProcessTest {
+ public:
+  ZipArchiverSandboxSetupTest()
+      : mojo_task_runner_(MojoTaskRunner::Create()),
+        zip_archiver_ptr_(nullptr, base::OnTaskRunnerDeleter(nullptr)) {
+    ZipArchiverSandboxSetupHooks setup_hooks(
+        mojo_task_runner_.get(), base::BindOnce([] {
+          FAIL() << "ZipArchiver sandbox connection error";
+        }));
+    CHECK_EQ(
+        RESULT_CODE_SUCCESS,
+        StartSandboxTarget(MakeCmdLine("ZipArchiverSandboxSetupTargetMain"),
+                           &setup_hooks, SandboxType::kTest));
+    zip_archiver_ptr_ = setup_hooks.TakeZipArchiverPtr();
+  }
+
+ protected:
+  void PostArchiveTask(base::win::ScopedHandle src_file_handle,
+                       base::win::ScopedHandle zip_file_handle,
+                       const std::string& filename_in_zip,
+                       const std::string& password,
+                       mojom::ZipArchiver::ArchiveCallback callback) {
+    mojo_task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(RunArchive, base::Unretained(zip_archiver_ptr_.get()),
+                       mojo::WrapPlatformFile(src_file_handle.Take()),
+                       mojo::WrapPlatformFile(zip_file_handle.Take()),
+                       filename_in_zip, password, std::move(callback)));
+  }
+
+ private:
+  static void RunArchive(mojom::ZipArchiverPtr* zip_archiver_ptr,
+                         mojo::ScopedHandle mojo_src_handle,
+                         mojo::ScopedHandle mojo_zip_handle,
+                         const std::string& filename_in_zip,
+                         const std::string& password,
+                         mojom::ZipArchiver::ArchiveCallback callback) {
+    DCHECK(zip_archiver_ptr);
+
+    (*zip_archiver_ptr)
+        ->Archive(std::move(mojo_src_handle), std::move(mojo_zip_handle),
+                  filename_in_zip, password, std::move(callback));
+  }
+
+  scoped_refptr<MojoTaskRunner> mojo_task_runner_;
+  UniqueZipArchiverPtr zip_archiver_ptr_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+};
+
+void OnArchiveDone(ZipArchiverResultCode* test_result_code,
+                   base::OnceClosure callback,
+                   ZipArchiverResultCode result_code) {
+  *test_result_code = result_code;
+  std::move(callback).Run();
+}
+
+}  // namespace
+
+MULTIPROCESS_TEST_MAIN(ZipArchiverSandboxSetupTargetMain) {
+  sandbox::TargetServices* sandbox_target_services =
+      sandbox::SandboxFactory::GetTargetServices();
+  CHECK(sandbox_target_services);
+
+  // |RunZipArchiverSandboxTarget| won't return. The mojo error handler will
+  // abort this process when the connection is broken.
+  RunZipArchiverSandboxTarget(*base::CommandLine::ForCurrentProcess(),
+                              sandbox_target_services);
+
+  return 0;
+}
+
+TEST_F(ZipArchiverSandboxSetupTest, Archive) {
+  ZipArchiverTestFile test_file;
+  test_file.Initialize();
+
+  base::File src_file(test_file.GetSourceFilePath(),
+                      base::File::FLAG_OPEN | base::File::FLAG_READ);
+  base::win::ScopedHandle src_file_handle(src_file.TakePlatformFile());
+  ASSERT_TRUE(src_file_handle.IsValid());
+
+  const base::FilePath zip_file_path =
+      test_file.GetSourceFilePath().AddExtension(L".zip");
+  base::File zip_file(zip_file_path,
+                      base::File::FLAG_CREATE | base::File::FLAG_WRITE);
+  base::win::ScopedHandle zip_file_handle(zip_file.TakePlatformFile());
+  ASSERT_TRUE(zip_file_handle.IsValid());
+
+  ZipArchiverResultCode test_result_code;
+  base::RunLoop loop;
+  PostArchiveTask(
+      std::move(src_file_handle), std::move(zip_file_handle),
+      kTestFilenameInZip, kTestPassword,
+      base::BindOnce(OnArchiveDone, &test_result_code, loop.QuitClosure()));
+  loop.Run();
+  EXPECT_EQ(test_result_code, ZipArchiverResultCode::kSuccess);
+  test_file.ExpectValidZipFile(zip_file_path, kTestFilenameInZip,
+                               kTestPassword);
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/zip_archiver/sandboxed_zip_archiver.cc b/chrome/chrome_cleaner/zip_archiver/sandboxed_zip_archiver.cc
new file mode 100644
index 0000000..32a9f6a
--- /dev/null
+++ b/chrome/chrome_cleaner/zip_archiver/sandboxed_zip_archiver.cc
@@ -0,0 +1,229 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/chrome_cleaner/zip_archiver/sandboxed_zip_archiver.h"
+
+#include <utility>
+
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/macros.h"
+#include "base/strings/strcat.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/synchronization/waitable_event.h"
+#include "base/win/scoped_handle.h"
+#include "chrome/chrome_cleaner/os/disk_util.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+
+namespace chrome_cleaner {
+
+namespace {
+
+using mojom::ZipArchiverResultCode;
+
+constexpr wchar_t kDefaultFileStreamSuffix[] = L"::$DATA";
+constexpr uint32_t kMinimizedReadAccess =
+    SYNCHRONIZE | FILE_READ_DATA | FILE_READ_ATTRIBUTES;
+constexpr uint32_t kMinimizedWriteAccess =
+    SYNCHRONIZE | FILE_WRITE_DATA | FILE_READ_ATTRIBUTES;
+
+// NTFS file stream can be specified by appending ":" to the filename. We remove
+// the default file stream "::$DATA" so it won't break the filename in the
+// following uses. For other file streams, we don't archive and ignore them.
+bool GetSanitizedFileName(const base::FilePath& path,
+                          base::string16* output_sanitized_filename) {
+  DCHECK(output_sanitized_filename);
+
+  base::string16 sanitized_filename = path.BaseName().AsUTF16Unsafe();
+  if (base::EndsWith(sanitized_filename, kDefaultFileStreamSuffix,
+                     base::CompareCase::INSENSITIVE_ASCII)) {
+    // Remove the default file stream suffix.
+    sanitized_filename.erase(
+        sanitized_filename.end() - wcslen(kDefaultFileStreamSuffix),
+        sanitized_filename.end());
+  }
+  // If there is any ":" in |sanitized_filename|, it either points to a
+  // non-default file stream or is abnormal. Don't archive in this case.
+  if (sanitized_filename.find(L":") != base::string16::npos)
+    return false;
+
+  *output_sanitized_filename = sanitized_filename;
+  return true;
+}
+
+void RunArchiver(mojom::ZipArchiverPtr* zip_archiver_ptr,
+                 mojo::ScopedHandle mojo_src_handle,
+                 mojo::ScopedHandle mojo_zip_handle,
+                 const std::string& filename,
+                 const std::string& password,
+                 mojom::ZipArchiver::ArchiveCallback callback) {
+  DCHECK(zip_archiver_ptr);
+
+  (*zip_archiver_ptr)
+      ->Archive(std::move(mojo_src_handle), std::move(mojo_zip_handle),
+                filename, password, std::move(callback));
+}
+
+void OnArchiveDone(ZipArchiverResultCode* return_code,
+                   base::WaitableEvent* waitable_event,
+                   ZipArchiverResultCode result_code) {
+  *return_code = static_cast<ZipArchiverResultCode>(result_code);
+  waitable_event->Signal();
+}
+
+}  // namespace
+
+SandboxedZipArchiver::SandboxedZipArchiver(
+    scoped_refptr<MojoTaskRunner> mojo_task_runner,
+    UniqueZipArchiverPtr zip_archiver_ptr,
+    const base::FilePath& dst_archive_folder,
+    const std::string& zip_password)
+    : mojo_task_runner_(mojo_task_runner),
+      zip_archiver_ptr_(std::move(zip_archiver_ptr)),
+      dst_archive_folder_(dst_archive_folder),
+      zip_password_(zip_password) {
+  // Make sure the |zip_archiver_ptr| is bound with the |mojo_task_runner|.
+  DCHECK(zip_archiver_ptr_.get_deleter().task_runner_ == mojo_task_runner);
+}
+
+SandboxedZipArchiver::~SandboxedZipArchiver() = default;
+
+// |SandboxedZipArchiver::Archive| archives the source file into a
+// password-protected zip file stored in the |dst_archive_folder|. The format of
+// zip file name is "|basename of the source file|_|hexdigest of the source file
+// hash|.zip".
+ZipArchiverResultCode SandboxedZipArchiver::Archive(
+    const base::FilePath& src_file_path,
+    base::FilePath* output_zip_file_path) {
+  DCHECK(output_zip_file_path);
+
+  // Open the source file with minimized rights for reading.
+  // Without |FILE_SHARE_WRITE| and |FILE_SHARE_DELETE|, |src_file_path| cannot
+  // be manipulated or replaced until |DoArchive| returns. This prevents the
+  // following checks from TOCTTOU. Because |base::IsLink| doesn't work on
+  // Windows, use |FILE_FLAG_OPEN_REPARSE_POINT| to open a symbolic link then
+  // check. To eliminate any TOCTTOU, use |FILE_FLAG_BACKUP_SEMANTICS| to open a
+  // directory then check.
+  base::File src_file(::CreateFile(
+      src_file_path.AsUTF16Unsafe().c_str(), kMinimizedReadAccess,
+      FILE_SHARE_READ, nullptr, OPEN_EXISTING,
+      FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, nullptr));
+  if (!src_file.IsValid()) {
+    LOG(ERROR) << "Unable to open the source file.";
+    return ZipArchiverResultCode::kErrorCannotOpenSourceFile;
+  }
+
+  BY_HANDLE_FILE_INFORMATION src_file_info;
+  if (!::GetFileInformationByHandle(src_file.GetPlatformFile(),
+                                    &src_file_info)) {
+    LOG(ERROR) << "Unable to get the source file information.";
+    return ZipArchiverResultCode::kErrorIO;
+  }
+
+  // Don't archive symbolic links.
+  if (src_file_info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
+    return ZipArchiverResultCode::kIgnoredSourceFile;
+
+  // Don't archive directories. And |ZipArchiver| shouldn't get called with a
+  // directory path.
+  if (src_file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
+    LOG(ERROR) << "Tried to archive a directory.";
+    return ZipArchiverResultCode::kIgnoredSourceFile;
+  }
+
+  base::string16 sanitized_src_filename;
+  if (!GetSanitizedFileName(src_file_path, &sanitized_src_filename))
+    return ZipArchiverResultCode::kIgnoredSourceFile;
+
+  // TODO(veranika): Check the source file size once the limit is determined.
+
+  std::string src_file_hash;
+  if (!ComputeSHA256DigestOfPath(src_file_path, &src_file_hash)) {
+    LOG(ERROR) << "Unable to hash the source file.";
+    return ZipArchiverResultCode::kErrorIO;
+  }
+
+  // Zip file name format: "|source basename|_|src_file_hash|.zip"
+  const base::FilePath zip_filename(
+      base::StrCat({sanitized_src_filename, L"_",
+                    base::UTF8ToUTF16(src_file_hash), L".zip"}));
+  const base::FilePath zip_file_path = dst_archive_folder_.Append(zip_filename);
+
+  // Fail if the zip file exists.
+  if (base::PathExists(zip_file_path))
+    return ZipArchiverResultCode::kZipFileExists;
+
+  // Create and open the zip file with minimized rights for writing.
+  base::File zip_file(::CreateFile(zip_file_path.AsUTF16Unsafe().c_str(),
+                                   kMinimizedWriteAccess, 0, nullptr,
+                                   CREATE_NEW, FILE_ATTRIBUTE_NORMAL, nullptr));
+  if (!zip_file.IsValid()) {
+    LOG(ERROR) << "Unable to create the zip file.";
+    return ZipArchiverResultCode::kErrorCannotCreateZipFile;
+  }
+
+  const std::string filename_in_zip = base::UTF16ToUTF8(sanitized_src_filename);
+  ZipArchiverResultCode result_code =
+      DoArchive(std::move(src_file), std::move(zip_file), filename_in_zip);
+  if (result_code != ZipArchiverResultCode::kSuccess) {
+    // The |zip_file| has been closed when returned from the scope of
+    // |DoArchive|. Delete the incomplete zip file directly.
+    if (!base::DeleteFile(zip_file_path, /*recursive=*/false))
+      LOG(ERROR) << "Failed to delete the incomplete zip file.";
+
+    return result_code;
+  }
+
+  *output_zip_file_path = zip_file_path;
+  return ZipArchiverResultCode::kSuccess;
+}
+
+ZipArchiverResultCode SandboxedZipArchiver::DoArchive(
+    base::File src_file,
+    base::File zip_file,
+    const std::string& filename_in_zip) {
+  ZipArchiverResultCode result_code;
+  base::WaitableEvent waitable_event(
+      base::WaitableEvent::ResetPolicy::MANUAL,
+      base::WaitableEvent::InitialState::NOT_SIGNALED);
+
+  // Unretained pointer of |zip_archiver_ptr_| is safe because its deleter
+  // is run on the same task runner. If |zip_archiver_ptr_| is destructed later,
+  // the deleter will be scheduled after this task.
+  mojo_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(
+          RunArchiver, base::Unretained(zip_archiver_ptr_.get()),
+          mojo::WrapPlatformFile(src_file.TakePlatformFile()),
+          mojo::WrapPlatformFile(zip_file.TakePlatformFile()), filename_in_zip,
+          zip_password_,
+          base::BindOnce(OnArchiveDone, &result_code, &waitable_event)));
+
+  waitable_event.Wait();
+  return result_code;
+}
+
+ResultCode SpawnZipArchiverSandbox(
+    const base::FilePath& dst_archive_folder,
+    const std::string& zip_password,
+    scoped_refptr<MojoTaskRunner> mojo_task_runner,
+    base::OnceClosure connection_error_handler,
+    std::unique_ptr<SandboxedZipArchiver>* sandboxed_zip_archiver) {
+  ZipArchiverSandboxSetupHooks setup_hooks(mojo_task_runner,
+                                           std::move(connection_error_handler));
+  DCHECK(sandboxed_zip_archiver);
+
+  ResultCode result_code =
+      SpawnSandbox(&setup_hooks, SandboxType::kZipArchiver);
+  if (result_code == RESULT_CODE_SUCCESS) {
+    *sandboxed_zip_archiver = std::make_unique<SandboxedZipArchiver>(
+        mojo_task_runner, setup_hooks.TakeZipArchiverPtr(), dst_archive_folder,
+        zip_password);
+  }
+
+  return result_code;
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/zip_archiver/sandboxed_zip_archiver.h b/chrome/chrome_cleaner/zip_archiver/sandboxed_zip_archiver.h
new file mode 100644
index 0000000..132ba78
--- /dev/null
+++ b/chrome/chrome_cleaner/zip_archiver/sandboxed_zip_archiver.h
@@ -0,0 +1,53 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_CHROME_CLEANER_ZIP_ARCHIVER_SANDBOXED_ZIP_ARCHIVER_H_
+#define CHROME_CHROME_CLEANER_ZIP_ARCHIVER_SANDBOXED_ZIP_ARCHIVER_H_
+
+#include <memory>
+#include <string>
+
+#include "base/bind.h"
+#include "base/files/file.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/sequenced_task_runner.h"
+#include "chrome/chrome_cleaner/interfaces/zip_archiver.mojom.h"
+#include "chrome/chrome_cleaner/ipc/mojo_task_runner.h"
+#include "chrome/chrome_cleaner/zip_archiver/broker/sandbox_setup.h"
+
+namespace chrome_cleaner {
+
+class SandboxedZipArchiver {
+ public:
+  SandboxedZipArchiver(scoped_refptr<MojoTaskRunner> mojo_task_runner,
+                       UniqueZipArchiverPtr zip_archiver_ptr,
+                       const base::FilePath& dst_archive_folder,
+                       const std::string& zip_password);
+  ~SandboxedZipArchiver();
+
+  mojom::ZipArchiverResultCode Archive(const base::FilePath& src_file_path,
+                                       base::FilePath* output_zip_file_path);
+
+ private:
+  mojom::ZipArchiverResultCode DoArchive(base::File src_file,
+                                         base::File zip_file,
+                                         const std::string& filename_in_zip);
+
+  scoped_refptr<MojoTaskRunner> mojo_task_runner_;
+  UniqueZipArchiverPtr zip_archiver_ptr_;
+  const base::FilePath dst_archive_folder_;
+  const std::string zip_password_;
+};
+
+ResultCode SpawnZipArchiverSandbox(
+    const base::FilePath& dst_archive_folder,
+    const std::string& zip_password,
+    scoped_refptr<MojoTaskRunner> mojo_task_runner,
+    base::OnceClosure connection_error_handler,
+    std::unique_ptr<SandboxedZipArchiver>* sandboxed_zip_archiver);
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_ZIP_ARCHIVER_SANDBOXED_ZIP_ARCHIVER_H_
diff --git a/chrome/chrome_cleaner/zip_archiver/sandboxed_zip_archiver_unittest.cc b/chrome/chrome_cleaner/zip_archiver/sandboxed_zip_archiver_unittest.cc
new file mode 100644
index 0000000..adffaaefa
--- /dev/null
+++ b/chrome/chrome_cleaner/zip_archiver/sandboxed_zip_archiver_unittest.cc
@@ -0,0 +1,312 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file.h"
+#include "base/macros.h"
+#include "base/memory/scoped_refptr.h"
+#include "base/sequenced_task_runner.h"
+#include "base/strings/strcat.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/multiprocess_test.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/win/scoped_handle.h"
+#include "chrome/chrome_cleaner/interfaces/zip_archiver.mojom.h"
+#include "chrome/chrome_cleaner/ipc/mojo_task_runner.h"
+#include "chrome/chrome_cleaner/os/disk_util.h"
+#include "chrome/chrome_cleaner/zip_archiver/broker/sandbox_setup.h"
+#include "chrome/chrome_cleaner/zip_archiver/sandboxed_zip_archiver.h"
+#include "chrome/chrome_cleaner/zip_archiver/target/sandbox_setup.h"
+#include "chrome/chrome_cleaner/zip_archiver/test_zip_archiver_util.h"
+#include "mojo/public/cpp/bindings/binding.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+#include "sandbox/win/src/sandbox.h"
+#include "sandbox/win/src/sandbox_factory.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/multiprocess_func_list.h"
+
+namespace chrome_cleaner {
+
+namespace {
+
+using mojom::ZipArchiverResultCode;
+
+constexpr char kTestPassword[] = "1234";
+constexpr char kTestSymlink[] = "a.link";
+constexpr uint32_t kProhibitedAccessPermissions[] = {
+    DELETE,       READ_CONTROL,     WRITE_DAC,
+    WRITE_OWNER,  FILE_APPEND_DATA, FILE_EXECUTE,
+    FILE_READ_EA, FILE_WRITE_EA,    FILE_WRITE_ATTRIBUTES};
+
+class ZipArchiverSandboxedArchiverTest : public base::MultiProcessTest {
+ public:
+  void SetUp() override {
+    scoped_refptr<MojoTaskRunner> mojo_task_runner = MojoTaskRunner::Create();
+    ZipArchiverSandboxSetupHooks setup_hooks(
+        mojo_task_runner.get(), base::BindOnce([] {
+          FAIL() << "ZipArchiver sandbox connection error";
+        }));
+    ASSERT_EQ(RESULT_CODE_SUCCESS,
+              StartSandboxTarget(MakeCmdLine("SandboxedZipArchiverTargetMain"),
+                                 &setup_hooks, SandboxType::kTest));
+    UniqueZipArchiverPtr zip_archiver_ptr = setup_hooks.TakeZipArchiverPtr();
+
+    test_file_.Initialize();
+    const base::FilePath& src_file_path = test_file_.GetSourceFilePath();
+
+    std::string src_file_hash;
+    ComputeSHA256DigestOfPath(src_file_path, &src_file_hash);
+
+    const base::FilePath& dst_archive_folder = test_file_.GetTempDirPath();
+    base::FilePath zip_filename(
+        base::StrCat({test_file_.GetSourceFilePath().BaseName().AsUTF16Unsafe(),
+                      L"_", base::UTF8ToUTF16(src_file_hash), L".zip"}));
+
+    expect_zip_file_path_ = dst_archive_folder.Append(zip_filename);
+
+    zip_archiver_ = std::make_unique<SandboxedZipArchiver>(
+        mojo_task_runner, std::move(zip_archiver_ptr), dst_archive_folder,
+        kTestPassword);
+  }
+
+ protected:
+  std::unique_ptr<SandboxedZipArchiver> zip_archiver_;
+  ZipArchiverTestFile test_file_;
+  base::FilePath expect_zip_file_path_;
+
+ private:
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+};
+
+// |ArchiverPermissionCheckerImpl| runs and handles |Archive| requests in the
+// sandbox child process. It checks if the parameters passed in the sandbox are
+// configured correctly. It doesn't do real archiving.
+class ArchiverPermissionCheckerImpl : public mojom::ZipArchiver {
+ public:
+  explicit ArchiverPermissionCheckerImpl(mojom::ZipArchiverRequest request)
+      : binding_(this, std::move(request)) {
+    binding_.set_connection_error_handler(base::BindOnce(
+        [] { FAIL() << "ZipArchiver sandbox connection error"; }));
+  }
+
+  ~ArchiverPermissionCheckerImpl() override = default;
+
+  void Archive(mojo::ScopedHandle src_file_handle,
+               mojo::ScopedHandle zip_file_handle,
+               const std::string& filename,
+               const std::string& password,
+               ArchiveCallback callback) override {
+    HANDLE raw_src_file_handle;
+    if (mojo::UnwrapPlatformFile(std::move(src_file_handle),
+                                 &raw_src_file_handle) != MOJO_RESULT_OK) {
+      std::move(callback).Run(ZipArchiverResultCode::kErrorInvalidParameter);
+      return;
+    }
+    base::File src_file(raw_src_file_handle);
+    if (!src_file.IsValid()) {
+      std::move(callback).Run(ZipArchiverResultCode::kErrorInvalidParameter);
+      return;
+    }
+
+    HANDLE raw_zip_file_handle;
+    if (mojo::UnwrapPlatformFile(std::move(zip_file_handle),
+                                 &raw_zip_file_handle) != MOJO_RESULT_OK) {
+      std::move(callback).Run(ZipArchiverResultCode::kErrorInvalidParameter);
+      return;
+    }
+    base::File zip_file(raw_zip_file_handle);
+    if (!zip_file.IsValid()) {
+      std::move(callback).Run(ZipArchiverResultCode::kErrorInvalidParameter);
+      return;
+    }
+
+    // Test general prohibited file access permissions.
+    for (uint32_t permission : kProhibitedAccessPermissions) {
+      if (HasPermission(src_file, permission) ||
+          HasPermission(zip_file, permission)) {
+        std::move(callback).Run(ZipArchiverResultCode::kErrorInvalidParameter);
+        return;
+      }
+    }
+
+    // Check if |src_file| and |zip_file| have incorrect file access
+    // permissions.
+    if (HasPermission(src_file, FILE_WRITE_DATA) ||
+        HasPermission(zip_file, FILE_READ_DATA)) {
+      std::move(callback).Run(ZipArchiverResultCode::kErrorInvalidParameter);
+      return;
+    }
+
+    std::move(callback).Run(ZipArchiverResultCode::kSuccess);
+  }
+
+ private:
+  static bool HasPermission(const base::File& file, uint32_t permission) {
+    HANDLE temp_handle;
+    if (::DuplicateHandle(::GetCurrentProcess(), file.GetPlatformFile(),
+                          ::GetCurrentProcess(), &temp_handle, permission,
+                          false, 0)) {
+      CloseHandle(temp_handle);
+      return true;
+    }
+    return false;
+  }
+
+  mojo::Binding<mojom::ZipArchiver> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(ArchiverPermissionCheckerImpl);
+};
+
+}  // namespace
+
+MULTIPROCESS_TEST_MAIN(SandboxedZipArchiverTargetMain) {
+  sandbox::TargetServices* sandbox_target_services =
+      sandbox::SandboxFactory::GetTargetServices();
+  CHECK(sandbox_target_services);
+
+  // |RunZipArchiverSandboxTarget| won't return. The mojo error handler will
+  // abort this process when the connection is broken.
+  RunZipArchiverSandboxTarget(*base::CommandLine::ForCurrentProcess(),
+                              sandbox_target_services);
+
+  return 0;
+}
+
+TEST_F(ZipArchiverSandboxedArchiverTest, Archive) {
+  base::FilePath output_zip_file_path;
+  EXPECT_EQ(zip_archiver_->Archive(test_file_.GetSourceFilePath(),
+                                   &output_zip_file_path),
+            ZipArchiverResultCode::kSuccess);
+
+  EXPECT_EQ(output_zip_file_path, expect_zip_file_path_);
+  test_file_.ExpectValidZipFile(
+      expect_zip_file_path_,
+      test_file_.GetSourceFilePath().BaseName().AsUTF8Unsafe(), kTestPassword);
+}
+
+TEST_F(ZipArchiverSandboxedArchiverTest, SourceFileNotFound) {
+  ASSERT_TRUE(base::DeleteFile(test_file_.GetSourceFilePath(), false));
+
+  base::FilePath output_zip_file_path;
+  EXPECT_EQ(zip_archiver_->Archive(test_file_.GetSourceFilePath(),
+                                   &output_zip_file_path),
+            ZipArchiverResultCode::kErrorCannotOpenSourceFile);
+}
+
+TEST_F(ZipArchiverSandboxedArchiverTest, ZipFileExists) {
+  base::File zip_file(expect_zip_file_path_, base::File::FLAG_CREATE);
+  ASSERT_TRUE(zip_file.IsValid());
+
+  base::FilePath output_zip_file_path;
+  EXPECT_EQ(zip_archiver_->Archive(test_file_.GetSourceFilePath(),
+                                   &output_zip_file_path),
+            ZipArchiverResultCode::kZipFileExists);
+}
+
+TEST_F(ZipArchiverSandboxedArchiverTest, SourceIsSymbolicLink) {
+  base::FilePath symlink_path =
+      test_file_.GetTempDirPath().AppendASCII(kTestSymlink);
+  ASSERT_TRUE(::CreateSymbolicLink(
+      symlink_path.AsUTF16Unsafe().c_str(),
+      test_file_.GetSourceFilePath().AsUTF16Unsafe().c_str(), 0));
+
+  base::FilePath output_zip_file_path;
+  EXPECT_EQ(zip_archiver_->Archive(symlink_path, &output_zip_file_path),
+            ZipArchiverResultCode::kIgnoredSourceFile);
+}
+
+TEST_F(ZipArchiverSandboxedArchiverTest, SourceIsDirectory) {
+  base::FilePath output_zip_file_path;
+  EXPECT_EQ(zip_archiver_->Archive(test_file_.GetTempDirPath(),
+                                   &output_zip_file_path),
+            ZipArchiverResultCode::kIgnoredSourceFile);
+}
+
+TEST_F(ZipArchiverSandboxedArchiverTest, SourceIsDefaultFileStream) {
+  base::FilePath stream_path(base::StrCat(
+      {test_file_.GetSourceFilePath().AsUTF16Unsafe(), L"::$data"}));
+
+  base::FilePath output_zip_file_path;
+  EXPECT_EQ(zip_archiver_->Archive(stream_path, &output_zip_file_path),
+            ZipArchiverResultCode::kSuccess);
+
+  EXPECT_EQ(output_zip_file_path, expect_zip_file_path_);
+  test_file_.ExpectValidZipFile(
+      expect_zip_file_path_,
+      test_file_.GetSourceFilePath().BaseName().AsUTF8Unsafe(), kTestPassword);
+}
+
+TEST_F(ZipArchiverSandboxedArchiverTest, SourceIsNonDefaultFileStream) {
+  base::FilePath stream_path(base::StrCat(
+      {test_file_.GetSourceFilePath().AsUTF16Unsafe(), L":stream:$data"}));
+  base::File stream_file(stream_path, base::File::FLAG_CREATE);
+  ASSERT_TRUE(stream_file.IsValid());
+
+  base::FilePath output_zip_file_path;
+  EXPECT_EQ(zip_archiver_->Archive(stream_path, &output_zip_file_path),
+            ZipArchiverResultCode::kIgnoredSourceFile);
+}
+
+namespace {
+
+// |ZipArchiverIsolationTest| uses |ArchiverPermissionCheckerImpl| to check the
+// sandbox configuration.
+class ZipArchiverIsolationTest : public base::MultiProcessTest {
+ public:
+  ZipArchiverIsolationTest()
+      : mojo_task_runner_(MojoTaskRunner::Create()),
+        impl_ptr_(nullptr, base::OnTaskRunnerDeleter(mojo_task_runner_)) {
+    UniqueZipArchiverPtr zip_archiver_ptr(
+        new mojom::ZipArchiverPtr(),
+        base::OnTaskRunnerDeleter(mojo_task_runner_));
+
+    // Initialize the |impl_ptr_| in the mojo task and wait until it completed.
+    base::RunLoop loop;
+    mojo_task_runner_->PostTask(
+        FROM_HERE,
+        base::BindOnce(
+            &ZipArchiverIsolationTest::InitializeArchiverPermissionCheckerImpl,
+            base::Unretained(this), zip_archiver_ptr.get(),
+            loop.QuitClosure()));
+    loop.Run();
+
+    test_file_.Initialize();
+
+    zip_archiver_ = std::make_unique<SandboxedZipArchiver>(
+        mojo_task_runner_, std::move(zip_archiver_ptr),
+        test_file_.GetTempDirPath(), kTestPassword);
+  }
+
+ protected:
+  std::unique_ptr<SandboxedZipArchiver> zip_archiver_;
+  ZipArchiverTestFile test_file_;
+
+ private:
+  void InitializeArchiverPermissionCheckerImpl(
+      mojom::ZipArchiverPtr* zip_archiver_ptr,
+      base::OnceClosure callback) {
+    impl_ptr_.reset(
+        new ArchiverPermissionCheckerImpl(mojo::MakeRequest(zip_archiver_ptr)));
+    std::move(callback).Run();
+  }
+
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  scoped_refptr<MojoTaskRunner> mojo_task_runner_;
+  std::unique_ptr<ArchiverPermissionCheckerImpl, base::OnTaskRunnerDeleter>
+      impl_ptr_;
+};
+
+}  // namespace
+
+TEST_F(ZipArchiverIsolationTest, CheckPermission) {
+  base::FilePath output_zip_file_path;
+  EXPECT_EQ(zip_archiver_->Archive(test_file_.GetSourceFilePath(),
+                                   &output_zip_file_path),
+            ZipArchiverResultCode::kSuccess);
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/zip_archiver/target/BUILD.gn b/chrome/chrome_cleaner/zip_archiver/target/BUILD.gn
new file mode 100644
index 0000000..01f15d9d
--- /dev/null
+++ b/chrome/chrome_cleaner/zip_archiver/target/BUILD.gn
@@ -0,0 +1,46 @@
+# Copyright 2018 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+static_library("common") {
+  sources = [
+    "sandbox_setup.cc",
+    "sandbox_setup.h",
+    "zip_archiver_impl.cc",
+    "zip_archiver_impl.h",
+  ]
+
+  deps = [
+    "//base:base",
+    "//chrome/chrome_cleaner/constants:common_strings",
+    "//chrome/chrome_cleaner/interfaces:zip_archiver_interface",
+    "//chrome/chrome_cleaner/ipc:mojo_task_runner",
+    "//chrome/chrome_cleaner/ipc:sandbox",
+    "//chrome/chrome_cleaner/os:common_os",
+    "//components/chrome_cleaner/public/constants:constants",
+    "//mojo/public/cpp/system:system",
+    "//sandbox/win:sandbox",
+    "//third_party/zlib:minizip",
+    "//third_party/zlib:zlib",
+  ]
+}
+
+source_set("unittest_sources") {
+  testonly = true
+
+  sources = [
+    "zip_archiver_impl_unittest.cc",
+  ]
+
+  deps = [
+    ":common",
+    "//base:base",
+    "//base/test:test_config",
+    "//base/test:test_support",
+    "//chrome/chrome_cleaner/interfaces:zip_archiver_interface",
+    "//chrome/chrome_cleaner/ipc:mojo_task_runner",
+    "//chrome/chrome_cleaner/zip_archiver:test_support",
+    "//mojo/public/cpp/system:system",
+    "//testing/gtest",
+  ]
+}
diff --git a/chrome/chrome_cleaner/zip_archiver/target/sandbox_setup.cc b/chrome/chrome_cleaner/zip_archiver/target/sandbox_setup.cc
new file mode 100644
index 0000000..422ccbf
--- /dev/null
+++ b/chrome/chrome_cleaner/zip_archiver/target/sandbox_setup.cc
@@ -0,0 +1,89 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/chrome_cleaner/zip_archiver/target/sandbox_setup.h"
+
+#include <memory>
+#include <utility>
+
+#include "base/memory/scoped_refptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/sequenced_task_runner.h"
+#include "chrome/chrome_cleaner/constants/chrome_cleaner_switches.h"
+#include "chrome/chrome_cleaner/ipc/mojo_sandbox_hooks.h"
+#include "chrome/chrome_cleaner/ipc/mojo_task_runner.h"
+#include "chrome/chrome_cleaner/os/early_exit.h"
+#include "chrome/chrome_cleaner/zip_archiver/target/zip_archiver_impl.h"
+
+namespace chrome_cleaner {
+
+namespace {
+
+class ZipArchiverSandboxTargetHooks : public MojoSandboxTargetHooks {
+ public:
+  explicit ZipArchiverSandboxTargetHooks(MojoTaskRunner* mojo_task_runner);
+  ~ZipArchiverSandboxTargetHooks() override;
+
+  // Sandbox hooks
+
+  ResultCode TargetDroppedPrivileges(
+      const base::CommandLine& command_line) override;
+
+ private:
+  void CreateZipArchiverImpl(mojom::ZipArchiverRequest request);
+
+  MojoTaskRunner* mojo_task_runner_;
+  base::MessageLoop message_loop_;
+  std::unique_ptr<ZipArchiverImpl, base::OnTaskRunnerDeleter>
+      zip_archiver_impl_;
+};
+
+ZipArchiverSandboxTargetHooks::ZipArchiverSandboxTargetHooks(
+    MojoTaskRunner* mojo_task_runner)
+    : mojo_task_runner_(mojo_task_runner),
+      zip_archiver_impl_(nullptr,
+                         base::OnTaskRunnerDeleter(mojo_task_runner_)) {}
+
+ZipArchiverSandboxTargetHooks::~ZipArchiverSandboxTargetHooks() = default;
+
+ResultCode ZipArchiverSandboxTargetHooks::TargetDroppedPrivileges(
+    const base::CommandLine& command_line) {
+  mojom::ZipArchiverRequest request(ExtractSandboxMessagePipe(command_line));
+
+  // This loop will run forever. Once the communication channel with the broker
+  // process is broken, mojo error handler will abort this process.
+  base::RunLoop run_loop;
+  mojo_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&ZipArchiverSandboxTargetHooks::CreateZipArchiverImpl,
+                     base::Unretained(this), std::move(request)));
+  run_loop.Run();
+
+  return RESULT_CODE_SUCCESS;
+}
+
+void ZipArchiverSandboxTargetHooks::CreateZipArchiverImpl(
+    mojom::ZipArchiverRequest request) {
+  // Replace the null pointer by the actual |ZipArchiverImpl|.
+  // Manually use |new| here because |make_unique| doesn't work with
+  // custom deleter.
+  zip_archiver_impl_.reset(
+      new ZipArchiverImpl(std::move(request), base::BindOnce(&EarlyExit, 1)));
+}
+
+}  // namespace
+
+ResultCode RunZipArchiverSandboxTarget(
+    const base::CommandLine& command_line,
+    sandbox::TargetServices* target_services) {
+  DCHECK(target_services);
+
+  scoped_refptr<MojoTaskRunner> mojo_task_runner = MojoTaskRunner::Create();
+  ZipArchiverSandboxTargetHooks target_hooks(mojo_task_runner.get());
+
+  return RunSandboxTarget(command_line, target_services, &target_hooks);
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/zip_archiver/target/sandbox_setup.h b/chrome/chrome_cleaner/zip_archiver/target/sandbox_setup.h
new file mode 100644
index 0000000..845787c0
--- /dev/null
+++ b/chrome/chrome_cleaner/zip_archiver/target/sandbox_setup.h
@@ -0,0 +1,20 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_CHROME_CLEANER_ZIP_ARCHIVER_TARGET_SANDBOX_SETUP_H_
+#define CHROME_CHROME_CLEANER_ZIP_ARCHIVER_TARGET_SANDBOX_SETUP_H_
+
+#include "base/command_line.h"
+#include "components/chrome_cleaner/public/constants/result_codes.h"
+#include "sandbox/win/src/sandbox.h"
+
+namespace chrome_cleaner {
+
+ResultCode RunZipArchiverSandboxTarget(
+    const base::CommandLine& command_line,
+    sandbox::TargetServices* target_services);
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_ZIP_ARCHIVER_TARGET_SANDBOX_SETUP_H_
diff --git a/chrome/chrome_cleaner/zip_archiver/target/zip_archiver_impl.cc b/chrome/chrome_cleaner/zip_archiver/target/zip_archiver_impl.cc
new file mode 100644
index 0000000..253eecf
--- /dev/null
+++ b/chrome/chrome_cleaner/zip_archiver/target/zip_archiver_impl.cc
@@ -0,0 +1,267 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/chrome_cleaner/zip_archiver/target/zip_archiver_impl.h"
+
+#include <algorithm>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include "base/files/file.h"
+#include "base/files/file_util.h"
+#include "base/logging.h"
+#include "base/numerics/safe_conversions.h"
+#include "base/time/time.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+#include "third_party/zlib/contrib/minizip/ioapi.h"
+#include "third_party/zlib/contrib/minizip/zip.h"
+#include "third_party/zlib/zlib.h"
+
+namespace chrome_cleaner {
+
+namespace {
+
+using mojom::ZipArchiverResultCode;
+
+constexpr int64_t kReadBufferSize = 4096;
+
+// Compression method is STORE(0)
+constexpr int16_t kCompressionMethod = 0;
+
+// Section 4.4.2 http://www.pkware.com/documents/casestudies/APPNOTE.TXT
+// The lower byte indicates the ZIP version(63 = 6.3) and the upper byte
+// indicates the file attribute compatibility(0 = MS-DOS). We would like to
+// choose the lowest version as possible to make it easier to decompress. ZIP
+// 6.3 is the lowest version which supports UTF-8 filename.
+constexpr uint16_t kVersionMadeBy = (0x0 << 8) | 63;
+
+// Section 4.4.4 http://www.pkware.com/documents/casestudies/APPNOTE.TXT
+// Setting the Language encoding flag so the file is told to be in UTF-8.
+constexpr uint16_t kLanguageEncodingFlag = 0x1 << 11;
+
+bool CalculateFileCrc32(base::File* file,
+                        const int64_t length,
+                        uint32_t* crc32_result) {
+  DCHECK(file);
+  DCHECK(crc32_result);
+
+  std::vector<char> buffer(kReadBufferSize);
+  int64_t offset = 0;
+  uint32_t crc32_value = 0;
+
+  while (offset < length) {
+    const int read_size = file->Read(
+        offset, buffer.data(), std::min(length - offset, kReadBufferSize));
+    if (read_size <= 0) {
+      LOG(ERROR) << "Unable to read the file when calculating CRC32.";
+      return false;
+    }
+    CHECK_LE(base::checked_cast<size_t>(read_size), buffer.size());
+
+    crc32_value = crc32(crc32_value, reinterpret_cast<uint8_t*>(buffer.data()),
+                        read_size);
+
+    offset += read_size;
+  }
+
+  *crc32_result = crc32_value;
+  return true;
+}
+
+// Set up the minizip IO interface. The default functions of the interface are
+// POSIX IO functions, which work with |FILE*| file objects. Therefore, we hook
+// the open function of the interface and directly return the |FILE*| object of
+// the opened zip file. So other default functions can operate correctly with
+// the returned |FILE*| object, including closing the file.
+bool InitializeZipIOInterface(base::File output_file,
+                              zlib_filefunc64_def* zip_func_table) {
+  DCHECK(zip_func_table);
+
+  FILE* output_file_ptr = base::FileToFILE(std::move(output_file), "wb");
+  if (output_file_ptr == nullptr) {
+    LOG(ERROR) << "Unable to open FILE* from the base::File object.";
+    return false;
+  }
+
+  // Initialize with the default POSIX IO functions.
+  fill_fopen64_filefunc(zip_func_table);
+  // Now the |output_file_ptr| is owned by the minizip.
+  zip_func_table->opaque = output_file_ptr;
+  // Return the |FILE*| object of the opened zip file.
+  zip_func_table->zopen64_file = [](void* opaque, const void* /*filename*/,
+                                    int /*mode*/) { return opaque; };
+
+  return true;
+}
+
+zip_fileinfo TimeToZipFileInfo(const base::Time& file_time) {
+  base::Time::Exploded file_time_parts;
+  file_time.LocalExplode(&file_time_parts);
+
+  zip_fileinfo zip_info = {};
+  // This if check works around the handling of the year value in
+  // contrib/minizip/zip.c in function zip64local_TmzDateToDosDate
+  // It assumes that dates below 1980 are in the double digit format.
+  // Hence the fail safe option is to leave the date unset. Some programs
+  // might show the unset date as 1980-0-0 which is invalid.
+  if (file_time_parts.year >= 1980) {
+    zip_info.tmz_date.tm_year = file_time_parts.year;
+    zip_info.tmz_date.tm_mon = file_time_parts.month - 1;
+    zip_info.tmz_date.tm_mday = file_time_parts.day_of_month;
+    zip_info.tmz_date.tm_hour = file_time_parts.hour;
+    zip_info.tmz_date.tm_min = file_time_parts.minute;
+    zip_info.tmz_date.tm_sec = file_time_parts.second;
+  }
+
+  return zip_info;
+}
+
+ZipArchiverResultCode AddToArchive(zipFile zip_object,
+                                   const std::string& filename_in_zip,
+                                   const std::string& password,
+                                   base::File src_file) {
+  base::File::Info file_info;
+  if (!src_file.GetInfo(&file_info)) {
+    LOG(ERROR) << "Unable to get the file information.";
+    return ZipArchiverResultCode::kErrorIO;
+  }
+
+  if (file_info.is_directory || file_info.is_symbolic_link) {
+    LOG(ERROR) << "The source file is a directory or a symbolic link.";
+    return ZipArchiverResultCode::kErrorInvalidParameter;
+  }
+
+  const int64_t src_length = file_info.size;
+
+  // TODO(veranika): Check the source file size once the limit is determined.
+
+  uint32_t src_crc32 = 0;
+  if (!CalculateFileCrc32(&src_file, src_length, &src_crc32)) {
+    LOG(ERROR) << "Failed to calculate the CRC32 of the source file.";
+    return ZipArchiverResultCode::kErrorIO;
+  }
+
+  const zip_fileinfo zip_info = TimeToZipFileInfo(file_info.last_modified);
+
+  if (zipOpenNewFileInZip4_64(
+          zip_object, filename_in_zip.c_str(), &zip_info,
+          /*extrafield_local=*/nullptr, /*size_extrafield_local=*/0,
+          /*extrafield_global=*/nullptr, /*size_extrafield_global=*/0,
+          /*comment=*/nullptr, kCompressionMethod, /*level=*/0, /*raw=*/0,
+          -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, password.c_str(),
+          src_crc32, kVersionMadeBy, kLanguageEncodingFlag,
+          /*zip64=*/1) != Z_OK) {
+    LOG(ERROR) << "Unable to create a file entry in the zip.";
+    return ZipArchiverResultCode::kErrorMinizipInternal;
+  }
+
+  std::vector<char> buffer(kReadBufferSize);
+  int64_t src_offset = 0;
+  while (src_offset < src_length) {
+    const int read_size =
+        src_file.Read(src_offset, buffer.data(),
+                      std::min(src_length - src_offset, kReadBufferSize));
+    if (read_size <= 0) {
+      LOG(ERROR) << "Unable to read the source file when archiving.";
+      return ZipArchiverResultCode::kErrorIO;
+    }
+    CHECK_LE(base::checked_cast<size_t>(read_size), buffer.size());
+    if (zipWriteInFileInZip(zip_object, buffer.data(), read_size) != Z_OK) {
+      LOG(ERROR) << "Unable to write data into the zip.";
+      return ZipArchiverResultCode::kErrorMinizipInternal;
+    }
+    src_offset += read_size;
+  }
+
+  if (zipCloseFileInZip(zip_object) != Z_OK) {
+    LOG(ERROR) << "Unable to close the file entry.";
+    return ZipArchiverResultCode::kErrorMinizipInternal;
+  }
+
+  return ZipArchiverResultCode::kSuccess;
+}
+
+}  // namespace
+
+ZipArchiverImpl::ZipArchiverImpl(mojom::ZipArchiverRequest request,
+                                 base::OnceClosure connection_error_handler)
+    : binding_(this, std::move(request)) {
+  binding_.set_connection_error_handler(std::move(connection_error_handler));
+}
+
+ZipArchiverImpl::~ZipArchiverImpl() = default;
+
+void ZipArchiverImpl::Archive(mojo::ScopedHandle src_file_handle,
+                              mojo::ScopedHandle zip_file_handle,
+                              const std::string& filename_in_zip,
+                              const std::string& password,
+                              ArchiveCallback callback) {
+  // Neither |filename_in_zip| nor |password| being empty will raise any error
+  // in the minizip internally. However, the produced zip file can't be
+  // decompressed by some zip tools. So these cases are rejected.
+  if (filename_in_zip.empty() || password.empty()) {
+    LOG(ERROR) << "Either filename or password is empty.";
+    std::move(callback).Run(ZipArchiverResultCode::kErrorInvalidParameter);
+    return;
+  }
+
+  HANDLE raw_src_file_handle;
+  if (mojo::UnwrapPlatformFile(std::move(src_file_handle),
+                               &raw_src_file_handle) != MOJO_RESULT_OK) {
+    LOG(ERROR) << "Unable to get the source HANDLE from mojo.";
+    std::move(callback).Run(ZipArchiverResultCode::kErrorInvalidParameter);
+    return;
+  }
+  base::File src_file(raw_src_file_handle);
+  if (!src_file.IsValid()) {
+    LOG(ERROR) << "Source file is invalid.";
+    std::move(callback).Run(ZipArchiverResultCode::kErrorInvalidParameter);
+    return;
+  }
+
+  HANDLE raw_zip_file_handle;
+  if (mojo::UnwrapPlatformFile(std::move(zip_file_handle),
+                               &raw_zip_file_handle) != MOJO_RESULT_OK) {
+    LOG(ERROR) << "Unable to get the destination HANDLE from mojo.";
+    std::move(callback).Run(ZipArchiverResultCode::kErrorInvalidParameter);
+    return;
+  }
+  base::File zip_file(raw_zip_file_handle);
+  if (!zip_file.IsValid()) {
+    LOG(ERROR) << "Destination file is invalid.";
+    std::move(callback).Run(ZipArchiverResultCode::kErrorInvalidParameter);
+    return;
+  }
+
+  zlib_filefunc64_def zip_func_table;
+  if (!InitializeZipIOInterface(std::move(zip_file), &zip_func_table)) {
+    LOG(ERROR) << "Failed to initialize the minizip IO interface.";
+    std::move(callback).Run(ZipArchiverResultCode::kErrorInvalidParameter);
+    return;
+  }
+
+  // Since the open function has been hooked in |InitializeZipIOInterface|,
+  // which doesn't need a file path, we just pass a dummy path to the |path|.
+  zipFile zip_object = zipOpen2_64(/*path=*/"", /*append=*/0,
+                                   /*globalcomment=*/nullptr, &zip_func_table);
+  if (zip_object == nullptr) {
+    LOG(ERROR) << "Unable to open the zip file.";
+    std::move(callback).Run(ZipArchiverResultCode::kErrorMinizipInternal);
+    return;
+  }
+
+  ZipArchiverResultCode result_code =
+      AddToArchive(zip_object, filename_in_zip, password, std::move(src_file));
+
+  if (zipClose(zip_object, /*global_comment=*/nullptr) != Z_OK) {
+    LOG(ERROR) << "Unable to close the zip file.";
+    if (result_code == ZipArchiverResultCode::kSuccess)
+      result_code = ZipArchiverResultCode::kErrorMinizipInternal;
+  }
+
+  std::move(callback).Run(result_code);
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/zip_archiver/target/zip_archiver_impl.h b/chrome/chrome_cleaner/zip_archiver/target/zip_archiver_impl.h
new file mode 100644
index 0000000..00ef670
--- /dev/null
+++ b/chrome/chrome_cleaner/zip_archiver/target/zip_archiver_impl.h
@@ -0,0 +1,35 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_CHROME_CLEANER_ZIP_ARCHIVER_TARGET_ZIP_ARCHIVER_IMPL_H_
+#define CHROME_CHROME_CLEANER_ZIP_ARCHIVER_TARGET_ZIP_ARCHIVER_IMPL_H_
+
+#include <string>
+
+#include "chrome/chrome_cleaner/interfaces/zip_archiver.mojom.h"
+#include "mojo/public/cpp/bindings/binding.h"
+
+namespace chrome_cleaner {
+
+class ZipArchiverImpl : public mojom::ZipArchiver {
+ public:
+  ZipArchiverImpl(mojom::ZipArchiverRequest request,
+                  base::OnceClosure connection_error_handler);
+  ~ZipArchiverImpl() override;
+
+  void Archive(mojo::ScopedHandle src_file_handle,
+               mojo::ScopedHandle zip_file_handle,
+               const std::string& filename,
+               const std::string& password,
+               ArchiveCallback callback) override;
+
+ private:
+  mojo::Binding<mojom::ZipArchiver> binding_;
+
+  DISALLOW_COPY_AND_ASSIGN(ZipArchiverImpl);
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_ZIP_ARCHIVER_TARGET_ZIP_ARCHIVER_IMPL_H_
diff --git a/chrome/chrome_cleaner/zip_archiver/target/zip_archiver_impl_unittest.cc b/chrome/chrome_cleaner/zip_archiver/target/zip_archiver_impl_unittest.cc
new file mode 100644
index 0000000..9ccf21f
--- /dev/null
+++ b/chrome/chrome_cleaner/zip_archiver/target/zip_archiver_impl_unittest.cc
@@ -0,0 +1,128 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/chrome_cleaner/zip_archiver/target/zip_archiver_impl.h"
+
+#include <utility>
+
+#include "base/bind.h"
+#include "base/files/file_util.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/win/scoped_handle.h"
+#include "chrome/chrome_cleaner/interfaces/zip_archiver.mojom.h"
+#include "chrome/chrome_cleaner/ipc/mojo_task_runner.h"
+#include "chrome/chrome_cleaner/zip_archiver/test_zip_archiver_util.h"
+#include "mojo/public/cpp/system/platform_handle.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace chrome_cleaner {
+
+namespace {
+
+using mojom::ZipArchiverResultCode;
+
+const char kTestFilenameInZip[] = "a.txt";
+const char kTestPassword[] = "1234";
+
+class ZipArchiverImplTest : public testing::Test {
+ public:
+  void SetUp() override {
+    test_file_.Initialize();
+    base::File src_file(test_file_.GetSourceFilePath(),
+                        base::File::FLAG_OPEN | base::File::FLAG_READ);
+    src_file_handle_ = base::win::ScopedHandle(src_file.TakePlatformFile());
+    ASSERT_TRUE(src_file_handle_.IsValid());
+
+    zip_file_path_ = test_file_.GetSourceFilePath().AddExtension(L".zip");
+    base::File zip_file(zip_file_path_,
+                        base::File::FLAG_CREATE | base::File::FLAG_WRITE);
+    zip_file_handle_ = base::win::ScopedHandle(zip_file.TakePlatformFile());
+    ASSERT_TRUE(zip_file_handle_.IsValid());
+  }
+
+ protected:
+  ZipArchiverTestFile test_file_;
+  base::win::ScopedHandle src_file_handle_;
+  base::win::ScopedHandle zip_file_handle_;
+  base::FilePath zip_file_path_;
+
+ private:
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+};
+
+void RunArchiver(base::win::ScopedHandle src_file_handle,
+                 base::win::ScopedHandle zip_file_handle,
+                 const std::string& filename,
+                 const std::string& password,
+                 mojom::ZipArchiver::ArchiveCallback callback) {
+  mojom::ZipArchiverPtr zip_archiver_ptr;
+  ZipArchiverImpl zip_archiver_impl(
+      mojo::MakeRequest(&zip_archiver_ptr),
+      /*connection_error_handler=*/base::DoNothing());
+  zip_archiver_impl.Archive(mojo::WrapPlatformFile(src_file_handle.Take()),
+                            mojo::WrapPlatformFile(zip_file_handle.Take()),
+                            filename, password, std::move(callback));
+}
+
+void OnArchiveDone(ZipArchiverResultCode* test_result_code,
+                   base::OnceClosure callback,
+                   ZipArchiverResultCode result_code) {
+  *test_result_code = result_code;
+  std::move(callback).Run();
+}
+
+void BindArchiverThenRun(base::win::ScopedHandle src_file_handle,
+                         base::win::ScopedHandle zip_file_handle,
+                         const std::string& filename_in_zip,
+                         const std::string& password,
+                         mojom::ZipArchiver::ArchiveCallback callback) {
+  scoped_refptr<MojoTaskRunner> task_runner = MojoTaskRunner::Create();
+
+  task_runner->PostTask(
+      FROM_HERE, base::BindOnce(RunArchiver, std::move(src_file_handle),
+                                std::move(zip_file_handle), filename_in_zip,
+                                password, std::move(callback)));
+}
+
+}  // namespace
+
+TEST_F(ZipArchiverImplTest, Archive) {
+  ZipArchiverResultCode test_result_code;
+  base::RunLoop loop;
+  BindArchiverThenRun(
+      std::move(src_file_handle_), std::move(zip_file_handle_),
+      kTestFilenameInZip, kTestPassword,
+      base::BindOnce(OnArchiveDone, &test_result_code, loop.QuitClosure()));
+  loop.Run();
+  EXPECT_EQ(test_result_code, ZipArchiverResultCode::kSuccess);
+  test_file_.ExpectValidZipFile(zip_file_path_, kTestFilenameInZip,
+                                kTestPassword);
+}
+
+TEST_F(ZipArchiverImplTest, EmptyFilename) {
+  ZipArchiverResultCode test_result_code;
+  base::RunLoop loop;
+  BindArchiverThenRun(
+      std::move(src_file_handle_), std::move(zip_file_handle_), "",
+      kTestPassword,
+      base::BindOnce(OnArchiveDone, &test_result_code, loop.QuitClosure()));
+  loop.Run();
+  EXPECT_EQ(test_result_code, ZipArchiverResultCode::kErrorInvalidParameter);
+}
+
+TEST_F(ZipArchiverImplTest, EmptyPassword) {
+  ZipArchiverResultCode test_result_code;
+  base::RunLoop loop;
+  BindArchiverThenRun(
+      std::move(src_file_handle_), std::move(zip_file_handle_),
+      kTestFilenameInZip, "",
+      base::BindOnce(OnArchiveDone, &test_result_code, loop.QuitClosure()));
+  loop.Run();
+  EXPECT_EQ(test_result_code, ZipArchiverResultCode::kErrorInvalidParameter);
+}
+
+// TODO(veranika): Add a test with a too big source file once the limit is
+// determined.
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/zip_archiver/test_zip_archiver_util.cc b/chrome/chrome_cleaner/zip_archiver/test_zip_archiver_util.cc
new file mode 100644
index 0000000..d091145
--- /dev/null
+++ b/chrome/chrome_cleaner/zip_archiver/test_zip_archiver_util.cc
@@ -0,0 +1,158 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/chrome_cleaner/zip_archiver/test_zip_archiver_util.h"
+
+#include <vector>
+
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/zlib/contrib/minizip/unzip.h"
+
+namespace chrome_cleaner {
+
+namespace {
+
+const char kTestContent[] = "Hello World";
+const base::Time::Exploded kTestFileTime = {
+    // Year
+    2018,
+    // Month
+    1,
+    // Day of week
+    1,
+    // Day of month
+    1,
+    // Hour
+    2,
+    // Minute
+    3,
+    // Second
+    5,
+    // Millisecond
+    0,
+};
+// The zip should be encrypted and use UTF-8 encoding.
+const uint16_t kExpectedZipFlag = 0x1 | (0x1 << 11);
+
+const int64_t kReadBufferSize = 4096;
+
+// The |day_of_week| in |base::Time::Exploded| won't be set correctly.
+// TODO(veranika): This is copied from
+// https://cs.chromium.org/chromium/src/chrome/browser/resources/chromeos/zip_archiver/cpp/volume_archive_minizip.cc.
+// It would be better to move it to //base.
+base::Time::Exploded ExplodeDosTime(const uint32_t dos_time) {
+  base::Time::Exploded time_part;
+  uint32_t remain_part = dos_time;
+  // 0-4bits, second divied by 2.
+  time_part.second = (remain_part & 0x1F) * 2;
+  remain_part >>= 5;
+  // 5-10bits, minute (0–59).
+  time_part.minute = remain_part & 0x3F;
+  remain_part >>= 6;
+  // 11-15bits, hour (0–23 on a 24-hour clock).
+  time_part.hour = remain_part & 0x1F;
+  remain_part >>= 5;
+  // 16-20bits, day of the month (1-31).
+  time_part.day_of_month = remain_part & 0x1F;
+  remain_part >>= 5;
+  // 21-24bits, month (1-23).
+  time_part.month = remain_part & 0xF;
+  remain_part >>= 4;
+  // 25-31bits, year offset from 1980.
+  time_part.year = (remain_part & 0x7F) + 1980;
+  return time_part;
+}
+
+}  // namespace
+
+ZipArchiverTestFile::ZipArchiverTestFile() : initialized_(false) {}
+
+ZipArchiverTestFile::~ZipArchiverTestFile() = default;
+
+void ZipArchiverTestFile::Initialize() {
+  // Can not be reinitialized.
+  CHECK(!initialized_);
+  initialized_ = true;
+
+  ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+  ASSERT_TRUE(
+      base::CreateTemporaryFileInDir(temp_dir_.GetPath(), &src_file_path_));
+
+  ASSERT_EQ(static_cast<size_t>(base::WriteFile(src_file_path_, kTestContent,
+                                                strlen(kTestContent))),
+            strlen(kTestContent));
+  // Set a fixed timestamp, so the modified time will be identical in every
+  // test.
+  base::Time file_time;
+  ASSERT_TRUE(base::Time::FromLocalExploded(kTestFileTime, &file_time));
+  ASSERT_TRUE(base::TouchFile(src_file_path_, file_time, file_time));
+}
+
+const base::FilePath& ZipArchiverTestFile::GetSourceFilePath() const {
+  return src_file_path_;
+}
+
+const base::FilePath& ZipArchiverTestFile::GetTempDirPath() const {
+  return temp_dir_.GetPath();
+}
+
+void ZipArchiverTestFile::ExpectValidZipFile(
+    const base::FilePath& zip_file_path,
+    const std::string& filename_in_zip,
+    const std::string& password) {
+  unzFile unzip_object = unzOpen64(zip_file_path.AsUTF8Unsafe().c_str());
+  ASSERT_NE(unzip_object, nullptr);
+  EXPECT_EQ(unzLocateFile(unzip_object, filename_in_zip.c_str(),
+                          /*iCaseSensitivity=*/1),
+            UNZ_OK);
+
+  unz_file_info64 file_info;
+  const size_t filename_length = strlen(filename_in_zip.c_str());
+  std::vector<char> filename(filename_length + 1);
+  EXPECT_EQ(unzGetCurrentFileInfo64(
+                unzip_object, &file_info, filename.data(), filename.size(),
+                /*extraField=*/nullptr, /*extraFieldBufferSize=*/0,
+                /*szComment=*/nullptr, /*commentBufferSize=*/0),
+            UNZ_OK);
+  EXPECT_EQ(file_info.flag & kExpectedZipFlag, kExpectedZipFlag);
+  // The compression method should be STORE(0).
+  EXPECT_EQ(file_info.compression_method, 0UL);
+  EXPECT_EQ(file_info.uncompressed_size, strlen(kTestContent));
+  EXPECT_EQ(file_info.size_filename, filename_in_zip.size());
+  EXPECT_STREQ(filename.data(), filename_in_zip.c_str());
+
+  base::Time::Exploded file_time = ExplodeDosTime(file_info.dosDate);
+  EXPECT_EQ(file_time.year, kTestFileTime.year);
+  EXPECT_EQ(file_time.month, kTestFileTime.month);
+  EXPECT_EQ(file_time.day_of_month, kTestFileTime.day_of_month);
+  EXPECT_EQ(file_time.hour, kTestFileTime.hour);
+  EXPECT_EQ(file_time.minute, kTestFileTime.minute);
+  // Dos time has a resolution of 2 seconds.
+  EXPECT_EQ(file_time.second, (kTestFileTime.second / 2) * 2);
+
+  EXPECT_EQ(unzOpenCurrentFilePassword(unzip_object, password.c_str()), UNZ_OK);
+
+  const size_t content_length = strlen(kTestContent);
+  std::vector<char> content;
+  uint8_t read_buffer[kReadBufferSize];
+  while (true) {
+    int read_size =
+        unzReadCurrentFile(unzip_object, read_buffer, kReadBufferSize);
+    EXPECT_GE(read_size, 0);
+    if (read_size == 0) {
+      break;
+    }
+    content.insert(content.end(), read_buffer, read_buffer + read_size);
+    if (content.size() > content_length) {
+      break;
+    }
+  }
+  EXPECT_EQ(content.size(), content_length);
+  EXPECT_EQ(std::string(content.begin(), content.end()), kTestContent);
+
+  EXPECT_EQ(unzCloseCurrentFile(unzip_object), UNZ_OK);
+  ASSERT_EQ(unzClose(unzip_object), UNZ_OK);
+}
+
+}  // namespace chrome_cleaner
diff --git a/chrome/chrome_cleaner/zip_archiver/test_zip_archiver_util.h b/chrome/chrome_cleaner/zip_archiver/test_zip_archiver_util.h
new file mode 100644
index 0000000..b8b29bb
--- /dev/null
+++ b/chrome/chrome_cleaner/zip_archiver/test_zip_archiver_util.h
@@ -0,0 +1,39 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_CHROME_CLEANER_ZIP_ARCHIVER_TEST_ZIP_ARCHIVER_UTIL_H_
+#define CHROME_CHROME_CLEANER_ZIP_ARCHIVER_TEST_ZIP_ARCHIVER_UTIL_H_
+
+#include <string>
+
+#include "base/files/file_util.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/win/scoped_handle.h"
+
+namespace chrome_cleaner {
+
+class ZipArchiverTestFile {
+ public:
+  ZipArchiverTestFile();
+  ~ZipArchiverTestFile();
+
+  void Initialize();
+
+  const base::FilePath& GetSourceFilePath() const;
+  const base::FilePath& GetTempDirPath() const;
+  void ExpectValidZipFile(const base::FilePath& zip_file_path,
+                          const std::string& filename_in_zip,
+                          const std::string& password);
+
+ private:
+  bool initialized_;
+  base::ScopedTempDir temp_dir_;
+  base::FilePath src_file_path_;
+
+  DISALLOW_COPY_AND_ASSIGN(ZipArchiverTestFile);
+};
+
+}  // namespace chrome_cleaner
+
+#endif  // CHROME_CHROME_CLEANER_ZIP_ARCHIVER_TEST_ZIP_ARCHIVER_UTIL_H_
diff --git a/chrome/common/media_router/mojo/media_router.mojom b/chrome/common/media_router/mojo/media_router.mojom
index 069d7cc..dc27cf81 100644
--- a/chrome/common/media_router/mojo/media_router.mojom
+++ b/chrome/common/media_router/mojo/media_router.mojom
@@ -591,4 +591,8 @@
       int32 initiator_tab_id,  // The tab used to register the stream.
       string desktop_stream_id,
       mirroring.mojom.MirroringServiceHost& request);
+  GetMirroringServiceHostForOffscreenTab(
+      url.mojom.Url presentation_url,
+      string presentation_id,
+      mirroring.mojom.MirroringServiceHost& request);
 };
diff --git a/chrome/installer/linux/debian/dist_package_versions.json b/chrome/installer/linux/debian/dist_package_versions.json
index 15f8c65..dcafc1c3 100644
--- a/chrome/installer/linux/debian/dist_package_versions.json
+++ b/chrome/installer/linux/debian/dist_package_versions.json
@@ -1,27 +1,27 @@
 {
     "Debian 10 (Buster)": {
-        "libappindicator3-1": "0.4.92-5",
-        "libasound2": "1.1.3-5",
+        "libappindicator3-1": "0.4.92-6",
+        "libasound2": "1.1.6-1",
         "libatk-bridge2.0-0": "2.26.2-1",
         "libatk1.0-0": "2.28.1-1",
-        "libc6": "2.27-3",
-        "libcairo2": "1.15.10-1",
-        "libcups2": "2.2.7-2",
-        "libdbus-1-3": "1.12.6-2",
-        "libexpat1": "2.2.5-3",
-        "libgcc1": "1:8-20180402-1",
-        "libgdk-pixbuf2.0-0": "2.36.11-2",
-        "libglib2.0-0": "2.56.0-4",
-        "libgtk-3-0": "3.22.29-3",
-        "libnspr4": "2:4.18-1",
-        "libnss3": "2:3.35-2",
-        "libpango-1.0-0": "1.42.0-1",
-        "libpangocairo-1.0-0": "1.42.0-1",
-        "libstdc++6": "8-20180402-1",
-        "libuuid1": "2.31.1-0.5",
-        "libx11-6": "2:1.6.5-1",
-        "libx11-xcb1": "2:1.6.5-1",
-        "libxcb1": "1.13-1",
+        "libc6": "2.27-5",
+        "libcairo2": "1.15.12-1",
+        "libcups2": "2.2.8-5",
+        "libdbus-1-3": "1.12.10-1",
+        "libexpat1": "2.2.6-1",
+        "libgcc1": "1:8.2.0-4",
+        "libgdk-pixbuf2.0-0": "2.36.12-2",
+        "libglib2.0-0": "2.56.1-2",
+        "libgtk-3-0": "3.22.30-2",
+        "libnspr4": "2:4.19-3",
+        "libnss3": "2:3.38-1",
+        "libpango-1.0-0": "1.42.4-1",
+        "libpangocairo-1.0-0": "1.42.4-1",
+        "libstdc++6": "8.2.0-4",
+        "libuuid1": "2.32.1-0.1",
+        "libx11-6": "2:1.6.6-1",
+        "libx11-xcb1": "2:1.6.6-1",
+        "libxcb1": "1.13-3",
         "libxcomposite1": "1:0.4.4-2",
         "libxcursor1": "1:1.1.15-1",
         "libxdamage1": "1:1.1.4-3",
@@ -40,7 +40,7 @@
         "libatk1.0-0": "2.14.0-1",
         "libc6": "2.19-18+deb8u10",
         "libcairo2": "1.14.0-2.1+deb8u2",
-        "libcups2": "1.7.5-11+deb8u1",
+        "libcups2": "1.7.5-11+deb8u4",
         "libdbus-1-3": "1.8.22-0+deb8u1",
         "libexpat1": "2.1.0-6+deb8u4",
         "libgcc1": "1:4.9.2-10+deb8u1",
@@ -53,11 +53,11 @@
         "libpangocairo-1.0-0": "1.36.8-3",
         "libstdc++6": "4.9.2-10+deb8u1",
         "libuuid1": "2.25.2-6",
-        "libx11-6": "2:1.6.2-3+deb8u1",
-        "libx11-xcb1": "2:1.6.2-3+deb8u1",
+        "libx11-6": "2:1.6.2-3+deb8u2",
+        "libx11-xcb1": "2:1.6.2-3+deb8u2",
         "libxcb1": "1.10-3+b1",
         "libxcomposite1": "1:0.4.4-1",
-        "libxcursor1": "1:1.1.14-1+deb8u1",
+        "libxcursor1": "1:1.1.14-1+deb8u2",
         "libxdamage1": "1:1.1.4-2+b1",
         "libxext6": "2:1.3.3-1",
         "libxfixes3": "1:5.0.1-2+deb8u1",
@@ -74,7 +74,7 @@
         "libatk1.0-0": "2.22.0-1",
         "libc6": "2.24-11+deb9u1",
         "libcairo2": "1.14.8-1",
-        "libcups2": "2.2.1-8+deb9u1",
+        "libcups2": "2.2.1-8+deb9u2",
         "libdbus-1-3": "1.10.26-0+deb9u1",
         "libexpat1": "2.2.0-2+deb9u1",
         "libgcc1": "1:6.3.0-18+deb9u1",
@@ -108,7 +108,7 @@
         "libatk1.0-0": "2.10.0-2ubuntu2",
         "libc6": "2.19-0ubuntu6.14",
         "libcairo2": "1.13.0~20140204-0ubuntu1.1",
-        "libcups2": "1.7.2-0ubuntu1.9",
+        "libcups2": "1.7.2-0ubuntu1.10",
         "libdbus-1-3": "1.6.18-0ubuntu4.4",
         "libexpat1": "2.1.0-4ubuntu1.4",
         "libgcc1": "1:4.9.3-0ubuntu4",
@@ -121,11 +121,11 @@
         "libpangocairo-1.0-0": "1.36.3-1ubuntu1.1",
         "libstdc++6": "4.8.4-2ubuntu1~14.04.4",
         "libuuid1": "2.20.1-5.1ubuntu20.9",
-        "libx11-6": "2:1.6.2-1ubuntu2",
-        "libx11-xcb1": "2:1.6.2-1ubuntu2",
+        "libx11-6": "2:1.6.2-1ubuntu2.1",
+        "libx11-xcb1": "2:1.6.2-1ubuntu2.1",
         "libxcb1": "1.10-2ubuntu1",
         "libxcomposite1": "1:0.4.4-1",
-        "libxcursor1": "1:1.1.14-1ubuntu0.14.04.1",
+        "libxcursor1": "1:1.1.14-1ubuntu0.14.04.2",
         "libxdamage1": "1:1.1.4-1ubuntu1",
         "libxext6": "2:1.3.2-1ubuntu0.0.14.04.1",
         "libxfixes3": "1:5.0.1-1ubuntu1.1",
@@ -142,24 +142,24 @@
         "libatk1.0-0": "2.18.0-1",
         "libc6": "2.23-0ubuntu10",
         "libcairo2": "1.14.6-1",
-        "libcups2": "2.1.3-4ubuntu0.4",
+        "libcups2": "2.1.3-4ubuntu0.5",
         "libdbus-1-3": "1.10.6-1ubuntu3.1",
         "libexpat1": "2.1.0-7ubuntu0.16.04.3",
         "libgcc1": "1:6.0.1-0ubuntu1",
         "libgdk-pixbuf2.0-0": "2.32.2-1ubuntu1.4",
-        "libglib2.0-0": "2.48.2-0ubuntu1",
+        "libglib2.0-0": "2.48.2-0ubuntu4",
         "libgtk-3-0": "3.18.9-1ubuntu3.3",
         "libnspr4": "2:4.13.1-0ubuntu0.16.04.1",
         "libnss3": "2:3.28.4-0ubuntu0.16.04.3",
         "libpango-1.0-0": "1.38.1-1",
         "libpangocairo-1.0-0": "1.38.1-1",
-        "libstdc++6": "5.4.0-6ubuntu1~16.04.9",
-        "libuuid1": "2.27.1-6ubuntu3.4",
-        "libx11-6": "2:1.6.3-1ubuntu2",
-        "libx11-xcb1": "2:1.6.3-1ubuntu2",
+        "libstdc++6": "5.4.0-6ubuntu1~16.04.10",
+        "libuuid1": "2.27.1-6ubuntu3.6",
+        "libx11-6": "2:1.6.3-1ubuntu2.1",
+        "libx11-xcb1": "2:1.6.3-1ubuntu2.1",
         "libxcb1": "1.11.1-1ubuntu1",
         "libxcomposite1": "1:0.4.4-1",
-        "libxcursor1": "1:1.1.14-1ubuntu0.16.04.1",
+        "libxcursor1": "1:1.1.14-1ubuntu0.16.04.2",
         "libxdamage1": "1:1.1.4-2",
         "libxext6": "2:1.3.3-1",
         "libxfixes3": "1:5.0.1-2",
@@ -176,7 +176,7 @@
         "libatk1.0-0": "2.26.0-2ubuntu1",
         "libc6": "2.26-0ubuntu2.1",
         "libcairo2": "1.14.10-1ubuntu1",
-        "libcups2": "2.2.4-7ubuntu3",
+        "libcups2": "2.2.4-7ubuntu3.1",
         "libdbus-1-3": "1.10.22-1ubuntu1",
         "libexpat1": "2.2.3-1",
         "libgcc1": "1:7.2.0-8ubuntu3.2",
@@ -188,7 +188,7 @@
         "libpango-1.0-0": "1.40.12-1",
         "libpangocairo-1.0-0": "1.40.12-1",
         "libstdc++6": "7.2.0-8ubuntu3.2",
-        "libuuid1": "2.30.1-0ubuntu4.1",
+        "libuuid1": "2.30.1-0ubuntu4.2",
         "libx11-6": "2:1.6.4-3",
         "libx11-xcb1": "2:1.6.4-3",
         "libxcb1": "1.12-1ubuntu1",
diff --git a/chrome/installer/linux/debian/download_repo_signing_keys.sh b/chrome/installer/linux/debian/download_repo_signing_keys.sh
index d8c2596d..d275764 100755
--- a/chrome/installer/linux/debian/download_repo_signing_keys.sh
+++ b/chrome/installer/linux/debian/download_repo_signing_keys.sh
@@ -19,6 +19,8 @@
   "75DDC3C4A499F1A18CB5F3C8CBF8D6FD518E17E1"
   # Debian Stable Release Key (9/stretch)
   "067E3C456BAE240ACEE88F6FEF0F382A1A7B6500"
+  # Debian Archive Automatic Signing Key (9/stretch)
+  "16E90B3FDF65EDE3AA7F323C04EE7237B7D453EC"
   # Ubuntu Archive Automatic Signing Key
   "630239CC130E1A7FD81A27B140976EAF437D05B5"
   # Ubuntu Archive Automatic Signing Key (2012)
diff --git a/chrome/installer/linux/debian/repo_signing_keys.gpg b/chrome/installer/linux/debian/repo_signing_keys.gpg
index 9cf5e93..6360348 100644
--- a/chrome/installer/linux/debian/repo_signing_keys.gpg
+++ b/chrome/installer/linux/debian/repo_signing_keys.gpg
Binary files differ
diff --git a/chrome/installer/setup/install.cc b/chrome/installer/setup/install.cc
index 2f67157..a3565b9e 100644
--- a/chrome/installer/setup/install.cc
+++ b/chrome/installer/setup/install.cc
@@ -54,7 +54,6 @@
 namespace {
 
 void LogShortcutOperation(ShellUtil::ShortcutLocation location,
-                          BrowserDistribution* dist,
                           const ShellUtil::ShortcutProperties& properties,
                           ShellUtil::ShortcutOperation operation,
                           bool failed) {
@@ -83,16 +82,12 @@
       message.append("Start menu ");
       break;
     case ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED:
-      message.append("Start menu/" +
-                     base::UTF16ToUTF8(dist->GetStartMenuShortcutSubfolder(
-                                     BrowserDistribution::SUBFOLDER_CHROME)) +
-                      " ");
+      NOTREACHED();
       break;
     case ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR:
-      message.append("Start menu/" +
-                     base::UTF16ToUTF8(dist->GetStartMenuShortcutSubfolder(
-                                     BrowserDistribution::SUBFOLDER_APPS)) +
-                     " ");
+      message.append(
+          "Start menu/" +
+          base::UTF16ToUTF8(InstallUtil::GetChromeAppsShortcutDirName()) + " ");
       break;
     default:
       NOTREACHED();
@@ -102,7 +97,7 @@
   if (properties.has_shortcut_name())
     message.append(base::UTF16ToUTF8(properties.shortcut_name));
   else
-    message.append(base::UTF16ToUTF8(dist->GetDisplayName()));
+    message.append(base::UTF16ToUTF8(InstallUtil::GetDisplayName()));
   message.push_back('"');
 
   message.append(" shortcut to ");
@@ -123,13 +118,11 @@
 
 void ExecuteAndLogShortcutOperation(
     ShellUtil::ShortcutLocation location,
-    BrowserDistribution* dist,
     const ShellUtil::ShortcutProperties& properties,
     ShellUtil::ShortcutOperation operation) {
-  LogShortcutOperation(location, dist, properties, operation, false);
-  if (!ShellUtil::CreateOrUpdateShortcut(location, dist, properties,
-                                         operation)) {
-    LogShortcutOperation(location, dist, properties, operation, true);
+  LogShortcutOperation(location, properties, operation, false);
+  if (!ShellUtil::CreateOrUpdateShortcut(location, properties, operation)) {
+    LogShortcutOperation(location, properties, operation, true);
   }
 }
 
@@ -365,8 +358,6 @@
   prefs.GetBool(master_preferences::kDoNotCreateTaskbarShortcut,
                 &do_not_create_taskbar_shortcut);
 
-  BrowserDistribution* dist = product.distribution();
-
   // The default operation on update is to overwrite shortcuts with the
   // currently desired properties, but do so only for shortcuts that still
   // exist.
@@ -395,9 +386,8 @@
 
   if (!do_not_create_desktop_shortcut ||
       shortcut_operation == ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING) {
-    ExecuteAndLogShortcutOperation(
-        ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist, base_properties,
-        shortcut_operation);
+    ExecuteAndLogShortcutOperation(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
+                                   base_properties, shortcut_operation);
   }
 
   if (!do_not_create_quick_launch_shortcut ||
@@ -406,9 +396,8 @@
     // install the per-user shortcut.
     ShellUtil::ShortcutProperties quick_launch_properties(base_properties);
     quick_launch_properties.level = ShellUtil::CURRENT_USER;
-    ExecuteAndLogShortcutOperation(
-        ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, dist,
-        quick_launch_properties, shortcut_operation);
+    ExecuteAndLogShortcutOperation(ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH,
+                                   quick_launch_properties, shortcut_operation);
   }
 
   ShellUtil::ShortcutProperties start_menu_properties(base_properties);
@@ -428,18 +417,16 @@
   // location.
   base::FilePath old_shortcut_path;
   ShellUtil::GetShortcutPath(
-      ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED, dist,
+      ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
       shortcut_level, &old_shortcut_path);
   if (base::PathExists(old_shortcut_path)) {
     ShellUtil::MoveExistingShortcut(
         ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
-        ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT,
-        dist, start_menu_properties);
+        ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT, start_menu_properties);
   }
 
-  ExecuteAndLogShortcutOperation(
-      ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT, dist,
-      start_menu_properties, shortcut_operation);
+  ExecuteAndLogShortcutOperation(ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT,
+                                 start_menu_properties, shortcut_operation);
 }
 
 void RegisterChromeOnMachine(const InstallerState& installer_state,
diff --git a/chrome/installer/setup/install_unittest.cc b/chrome/installer/setup/install_unittest.cc
index 1087d55da..1dd4a2a 100644
--- a/chrome/installer/setup/install_unittest.cc
+++ b/chrome/installer/setup/install_unittest.cc
@@ -210,9 +210,9 @@
   void SetUp() override {
     EXPECT_EQ(S_OK, CoInitialize(NULL));
 
-    dist_ = BrowserDistribution::GetDistribution();
-    ASSERT_TRUE(dist_ != NULL);
-    product_.reset(new installer::Product(dist_));
+    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
+    ASSERT_TRUE(dist);
+    product_.reset(new installer::Product(dist));
 
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     chrome_exe_ = temp_dir_.GetPath().Append(installer::kChromeExe);
@@ -248,7 +248,8 @@
     common_start_menu_override_.reset(new base::ScopedPathOverride(
         base::DIR_COMMON_START_MENU, fake_common_start_menu_.GetPath()));
 
-    base::string16 shortcut_name(dist_->GetShortcutName() + installer::kLnkExt);
+    base::string16 shortcut_name(InstallUtil::GetShortcutName() +
+                                 installer::kLnkExt);
 
     user_desktop_shortcut_ = fake_user_desktop_.GetPath().Append(shortcut_name);
     user_quick_launch_shortcut_ =
@@ -257,8 +258,7 @@
         fake_start_menu_.GetPath().Append(shortcut_name);
     user_start_menu_subdir_shortcut_ =
         fake_start_menu_.GetPath()
-            .Append(dist_->GetStartMenuShortcutSubfolder(
-                BrowserDistribution::SUBFOLDER_CHROME))
+            .Append(InstallUtil::GetChromeShortcutDirNameDeprecated())
             .Append(shortcut_name);
     system_desktop_shortcut_ =
         fake_common_desktop_.GetPath().Append(shortcut_name);
@@ -266,8 +266,7 @@
         fake_common_start_menu_.GetPath().Append(shortcut_name);
     system_start_menu_subdir_shortcut_ =
         fake_common_start_menu_.GetPath()
-            .Append(dist_->GetStartMenuShortcutSubfolder(
-                BrowserDistribution::SUBFOLDER_CHROME))
+            .Append(InstallUtil::GetChromeShortcutDirNameDeprecated())
             .Append(shortcut_name);
   }
 
@@ -309,7 +308,6 @@
   base::win::ShortcutProperties expected_properties_;
   base::win::ShortcutProperties expected_start_menu_properties_;
 
-  BrowserDistribution* dist_;
   base::FilePath chrome_exe_;
   std::unique_ptr<installer::Product> product_;
   std::unique_ptr<installer::MasterPreferences> prefs_;
diff --git a/chrome/installer/setup/install_worker.cc b/chrome/installer/setup/install_worker.cc
index e12e73e1b..88fb3c5 100644
--- a/chrome/installer/setup/install_worker.cc
+++ b/chrome/installer/setup/install_worker.cc
@@ -124,18 +124,12 @@
   }
 }
 
-base::string16 GetRegCommandKey(BrowserDistribution* dist,
-                                const wchar_t* name) {
-  return GetRegistrationDataCommandKey(dist->GetAppRegistrationData(), name);
-}
-
 // A callback invoked by |work_item| that adds firewall rules for Chrome. Rules
 // are left in-place on rollback unless |remove_on_rollback| is true. This is
 // the case for new installs only. Updates and overinstalls leave the rule
 // in-place on rollback since a previous install of Chrome will be used in that
 // case.
 bool AddFirewallRulesCallback(bool system_level,
-                              BrowserDistribution* dist,
                               const base::FilePath& chrome_path,
                               bool remove_on_rollback,
                               const CallbackWorkItem& work_item) {
@@ -144,7 +138,7 @@
     return true;
 
   std::unique_ptr<FirewallManager> manager =
-      FirewallManager::Create(dist, chrome_path);
+      FirewallManager::Create(chrome_path);
   if (!manager) {
     LOG(ERROR) << "Failed creating a FirewallManager. Continuing with install.";
     return true;
@@ -166,13 +160,11 @@
 
 // Adds work items to |list| to create firewall rules.
 void AddFirewallRulesWorkItems(const InstallerState& installer_state,
-                               BrowserDistribution* dist,
                                bool is_new_install,
                                WorkItemList* list) {
   list->AddCallbackWorkItem(
       base::Bind(&AddFirewallRulesCallback,
                  installer_state.system_install(),
-                 dist,
                  installer_state.target_path().Append(kChromeExe),
                  is_new_install));
 }
@@ -508,12 +500,10 @@
     base::string16 uninstall_reg = install_static::GetUninstallRegistryPath();
     install_list->AddCreateRegKeyWorkItem(
         reg_root, uninstall_reg, KEY_WOW64_32KEY);
-    install_list->AddSetRegValueWorkItem(reg_root,
-                                         uninstall_reg,
+    install_list->AddSetRegValueWorkItem(reg_root, uninstall_reg,
                                          KEY_WOW64_32KEY,
                                          installer::kUninstallDisplayNameField,
-                                         browser_dist->GetDisplayName(),
-                                         true);
+                                         InstallUtil::GetDisplayName(), true);
     install_list->AddSetRegValueWorkItem(
         reg_root,
         uninstall_reg,
@@ -598,22 +588,17 @@
 // Create Version key for a product (if not already present) and sets the new
 // product version as the last step.
 void AddVersionKeyWorkItems(HKEY root,
-                            const base::string16& version_key,
+                            const base::string16& clients_key,
                             const base::string16& product_name,
                             const base::Version& new_version,
                             bool add_language_identifier,
                             WorkItemList* list) {
-  list->AddCreateRegKeyWorkItem(root, version_key, KEY_WOW64_32KEY);
+  list->AddCreateRegKeyWorkItem(root, clients_key, KEY_WOW64_32KEY);
 
-  list->AddSetRegValueWorkItem(root,
-                               version_key,
-                               KEY_WOW64_32KEY,
-                               google_update::kRegNameField,
-                               product_name,
+  list->AddSetRegValueWorkItem(root, clients_key, KEY_WOW64_32KEY,
+                               google_update::kRegNameField, product_name,
                                true);  // overwrite name also
-  list->AddSetRegValueWorkItem(root,
-                               version_key,
-                               KEY_WOW64_32KEY,
+  list->AddSetRegValueWorkItem(root, clients_key, KEY_WOW64_32KEY,
                                google_update::kRegOopcrashesField,
                                static_cast<DWORD>(1),
                                false);  // set during first install
@@ -624,16 +609,11 @@
     base::string16 language(GetCurrentTranslation());
     if (base::LowerCaseEqualsASCII(language, "en-us"))
       language.resize(2);
-    list->AddSetRegValueWorkItem(root,
-                                 version_key,
-                                 KEY_WOW64_32KEY,
-                                 google_update::kRegLangField,
-                                 language,
+    list->AddSetRegValueWorkItem(root, clients_key, KEY_WOW64_32KEY,
+                                 google_update::kRegLangField, language,
                                  false);  // do not overwrite language
   }
-  list->AddSetRegValueWorkItem(root,
-                               version_key,
-                               KEY_WOW64_32KEY,
+  list->AddSetRegValueWorkItem(root, clients_key, KEY_WOW64_32KEY,
                                google_update::kRegVersionField,
                                ASCIIToUTF16(new_version.GetString()),
                                true);  // overwrite version
@@ -714,23 +694,22 @@
         installer_state.GetInstallerDirectory(new_version).Append(
             setup_path.BaseName()));
 
-    BrowserDistribution* dist = installer_state.product().distribution();
-    const base::string16 version_key(dist->GetVersionKey());
+    const base::string16 clients_key(install_static::GetClientsKeyPath());
 
     if (current_version) {
       in_use_update_work_items->AddSetRegValueWorkItem(
-          root, version_key, KEY_WOW64_32KEY,
+          root, clients_key, KEY_WOW64_32KEY,
           google_update::kRegOldVersionField,
           ASCIIToUTF16(current_version->GetString()), true);
     }
     if (critical_version.IsValid()) {
       in_use_update_work_items->AddSetRegValueWorkItem(
-          root, version_key, KEY_WOW64_32KEY,
+          root, clients_key, KEY_WOW64_32KEY,
           google_update::kRegCriticalVersionField,
           ASCIIToUTF16(critical_version.GetString()), true);
     } else {
       in_use_update_work_items->AddDeleteRegValueWorkItem(
-          root, version_key, KEY_WOW64_32KEY,
+          root, clients_key, KEY_WOW64_32KEY,
           google_update::kRegCriticalVersionField);
     }
 
@@ -743,7 +722,7 @@
       product_rename_cmd.AppendSwitch(switches::kVerboseLogging);
     InstallUtil::AppendModeSwitch(&product_rename_cmd);
     in_use_update_work_items->AddSetRegValueWorkItem(
-        root, version_key, KEY_WOW64_32KEY, google_update::kRegRenameCmdField,
+        root, clients_key, KEY_WOW64_32KEY, google_update::kRegRenameCmdField,
         product_rename_cmd.GetCommandLineString(), true);
 
     post_install_task_list->AddWorkItem(in_use_update_work_items.release());
@@ -757,15 +736,14 @@
     regular_update_work_items->set_log_message("RegularUpdateWorkItemList");
 
     // Since this was not an in-use-update, delete 'opv', 'cpv', and 'cmd' keys.
-    BrowserDistribution* dist = installer_state.product().distribution();
-    const base::string16 version_key(dist->GetVersionKey());
+    const base::string16 clients_key(install_static::GetClientsKeyPath());
     regular_update_work_items->AddDeleteRegValueWorkItem(
-        root, version_key, KEY_WOW64_32KEY, google_update::kRegOldVersionField);
+        root, clients_key, KEY_WOW64_32KEY, google_update::kRegOldVersionField);
     regular_update_work_items->AddDeleteRegValueWorkItem(
-        root, version_key, KEY_WOW64_32KEY,
+        root, clients_key, KEY_WOW64_32KEY,
         google_update::kRegCriticalVersionField);
     regular_update_work_items->AddDeleteRegValueWorkItem(
-        root, version_key, KEY_WOW64_32KEY, google_update::kRegRenameCmdField);
+        root, clients_key, KEY_WOW64_32KEY, google_update::kRegRenameCmdField);
 
     post_install_task_list->AddWorkItem(regular_update_work_items.release());
   }
@@ -874,9 +852,9 @@
   AddUninstallShortcutWorkItems(installer_state, setup_path, new_version,
                                 product, install_list);
 
-  BrowserDistribution* dist = product.distribution();
-  AddVersionKeyWorkItems(root, dist->GetVersionKey(), dist->GetDisplayName(),
-                         new_version, add_language_identifier, install_list);
+  AddVersionKeyWorkItems(root, install_static::GetClientsKeyPath(),
+                         InstallUtil::GetDisplayName(), new_version,
+                         add_language_identifier, install_list);
 
   AddCleanupDeprecatedPerUserRegistrationsWorkItems(product, install_list);
 
@@ -888,7 +866,7 @@
   AddEnterpriseEnrollmentWorkItems(installer_state, setup_path, new_version,
                                    product, install_list);
 #endif
-  AddFirewallRulesWorkItems(installer_state, dist, current_version == nullptr,
+  AddFirewallRulesWorkItems(installer_state, current_version == nullptr,
                             install_list);
 
   // We don't have a version check for Win10+ here so that Windows upgrades
@@ -1001,11 +979,9 @@
                              const Product& product,
                              WorkItemList* list) {
   DCHECK(installer_state.operation() != InstallerState::UNINSTALL);
-  BrowserDistribution* dist = product.distribution();
 
   if (!installer_state.system_install()) {
-    VLOG(1) << "No Active Setup processing to do for user-level "
-            << dist->GetDisplayName();
+    VLOG(1) << "No Active Setup processing to do for user-level Chrome";
     return;
   }
   DCHECK(installer_state.RequiresActiveSetup());
@@ -1016,12 +992,8 @@
   VLOG(1) << "Adding registration items for Active Setup.";
   list->AddCreateRegKeyWorkItem(
       root, active_setup_path, WorkItem::kWow64Default);
-  list->AddSetRegValueWorkItem(root,
-                               active_setup_path,
-                               WorkItem::kWow64Default,
-                               L"",
-                               dist->GetDisplayName(),
-                               true);
+  list->AddSetRegValueWorkItem(root, active_setup_path, WorkItem::kWow64Default,
+                               L"", InstallUtil::GetDisplayName(), true);
 
   base::FilePath active_setup_exe(installer_state.GetInstallerDirectory(
       new_version).Append(kActiveSetupExe));
@@ -1039,11 +1011,8 @@
 
   // TODO(grt): http://crbug.com/75152 Write a reference to a localized
   // resource.
-  list->AddSetRegValueWorkItem(root,
-                               active_setup_path,
-                               WorkItem::kWow64Default,
-                               L"Localized Name",
-                               dist->GetDisplayName(),
+  list->AddSetRegValueWorkItem(root, active_setup_path, WorkItem::kWow64Default,
+                               L"Localized Name", InstallUtil::GetDisplayName(),
                                true);
 
   list->AddSetRegValueWorkItem(root,
@@ -1079,8 +1048,7 @@
                            const Product& product,
                            WorkItemList* install_list) {
   const HKEY root_key = installer_state.root_key();
-  base::string16 cmd_key(
-      GetRegCommandKey(product.distribution(), kCmdOnOsUpgrade));
+  const base::string16 cmd_key(GetCommandKey(kCmdOnOsUpgrade));
 
   if (installer_state.operation() == InstallerState::UNINSTALL) {
     install_list->AddDeleteRegKeyWorkItem(root_key, cmd_key, KEY_WOW64_32KEY)
@@ -1115,8 +1083,7 @@
     return;
 
   const HKEY root_key = installer_state.root_key();
-  const base::string16 cmd_key(
-      GetRegCommandKey(product.distribution(), kCmdStoreDMToken));
+  const base::string16 cmd_key(GetCommandKey(kCmdStoreDMToken));
 
   if (installer_state.operation() == InstallerState::UNINSTALL) {
     install_list->AddDeleteRegKeyWorkItem(root_key, cmd_key, KEY_WOW64_32KEY)
diff --git a/chrome/installer/setup/installer_state.cc b/chrome/installer/setup/installer_state.cc
index 2b04463..53832b2a 100644
--- a/chrome/installer/setup/installer_state.cc
+++ b/chrome/installer/setup/installer_state.cc
@@ -71,10 +71,9 @@
   const bool is_uninstall = command_line.HasSwitch(switches::kUninstall);
 
   Product* p = AddProductFromPreferences(prefs, machine_state);
-  BrowserDistribution* dist = p->distribution();
-  VLOG(1) << (is_uninstall ? "Uninstall" : "Install")
-          << " distribution: " << dist->GetDisplayName();
+  VLOG(1) << (is_uninstall ? "Uninstall Chrome" : "Install Chrome");
 
+  BrowserDistribution* dist = p->distribution();
   state_key_ = dist->GetStateKey();
 
   if (is_uninstall) {
diff --git a/chrome/installer/setup/installer_state_unittest.cc b/chrome/installer/setup/installer_state_unittest.cc
index 01d2041..04bdfbed 100644
--- a/chrome/installer/setup/installer_state_unittest.cc
+++ b/chrome/installer/setup/installer_state_unittest.cc
@@ -90,8 +90,8 @@
   {
     RegistryOverrideManager override_manager;
     ASSERT_NO_FATAL_FAILURE(override_manager.OverrideRegistry(root));
-    BrowserDistribution* dist = BrowserDistribution::GetDistribution();
-    RegKey chrome_key(root, dist->GetVersionKey().c_str(), KEY_ALL_ACCESS);
+    RegKey chrome_key(root, install_static::GetClientsKeyPath().c_str(),
+                      KEY_ALL_ACCESS);
     EXPECT_TRUE(chrome_key.Valid());
     if (chrome_key.Valid()) {
       chrome_key.WriteValue(google_update::kRegVersionField,
diff --git a/chrome/installer/setup/setup_main.cc b/chrome/installer/setup/setup_main.cc
index a20887b..bc9d0efa 100644
--- a/chrome/installer/setup/setup_main.cc
+++ b/chrome/installer/setup/setup_main.cc
@@ -445,15 +445,14 @@
   // Add work items to delete Chrome's "opv", "cpv", and "cmd" values.
   // TODO(grt): Clean this up; https://crbug.com/577816.
   HKEY reg_root = installer_state->root_key();
-  base::string16 version_key;
-  version_key = installer_state->product().distribution()->GetVersionKey();
-  install_list->AddDeleteRegValueWorkItem(reg_root, version_key,
+  const base::string16 clients_key = install_static::GetClientsKeyPath();
+  install_list->AddDeleteRegValueWorkItem(reg_root, clients_key,
                                           KEY_WOW64_32KEY,
                                           google_update::kRegOldVersionField);
   install_list->AddDeleteRegValueWorkItem(
-      reg_root, version_key, KEY_WOW64_32KEY,
+      reg_root, clients_key, KEY_WOW64_32KEY,
       google_update::kRegCriticalVersionField);
-  install_list->AddDeleteRegValueWorkItem(reg_root, version_key,
+  install_list->AddDeleteRegValueWorkItem(reg_root, clients_key,
                                           KEY_WOW64_32KEY,
                                           google_update::kRegRenameCmdField);
   // old_chrome.exe is still in use in most cases, so ignore failures here.
@@ -576,8 +575,7 @@
     VLOG(1) << "version on the system: "
             << product_state->version().GetString();
   } else if (!force_uninstall) {
-    LOG(ERROR) << product.distribution()->GetDisplayName()
-               << " not found for uninstall.";
+    LOG(ERROR) << "Chrome not found for uninstall.";
     return installer::CHROME_NOT_INSTALLED;
   }
 
@@ -718,7 +716,7 @@
 
 // Creates the sentinel indicating that the EULA was required and has been
 // accepted.
-bool CreateEULASentinel(BrowserDistribution* dist) {
+bool CreateEULASentinel() {
   base::FilePath eula_sentinel;
   if (!InstallUtil::GetEULASentinelFilePath(&eula_sentinel))
     return false;
@@ -743,7 +741,7 @@
     static const wchar_t kPleaseUninstallYourChromeMessage[] =
         L"You already have a full-installation (non-dev) of %1ls, please "
         L"uninstall it first using Add/Remove Programs in the control panel.";
-    base::string16 name(chrome_dist->GetDisplayName());
+    base::string16 name(InstallUtil::GetDisplayName());
     base::string16 message(
         base::StringPrintf(kPleaseUninstallYourChromeMessage, name.c_str()));
 
@@ -769,8 +767,8 @@
     ShellUtil::AddDefaultShortcutProperties(chrome_exe, &shortcut_properties);
     shortcut_properties.set_pin_to_taskbar(true);
     ShellUtil::CreateOrUpdateShortcut(
-        ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT, chrome_dist,
-        shortcut_properties, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS);
+        ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT, shortcut_properties,
+        ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS);
 
     // Register Chrome at user-level and make it default.
     if (ShellUtil::CanMakeChromeDefaultUnattended()) {
@@ -860,7 +858,7 @@
     if (installer::EULA_REJECTED != *exit_code) {
       if (GoogleUpdateSettings::SetEULAConsent(
               *original_state, BrowserDistribution::GetDistribution(), true)) {
-        CreateEULASentinel(BrowserDistribution::GetDistribution());
+        CreateEULASentinel();
       }
     }
   } else if (cmd_line.HasSwitch(installer::switches::kConfigureUserSettings)) {
@@ -1159,14 +1157,11 @@
     bool proceed_with_installation = true;
 
     if (!IsDowngradeAllowed(prefs)) {
-      const Product& product = installer_state.product();
       const ProductState* product_state =
           original_state.GetProductState(system_install);
       if (product_state != NULL &&
           (product_state->version().CompareTo(*installer_version) > 0)) {
-        LOG(ERROR) << "Higher version of "
-                   << product.distribution()->GetDisplayName()
-                   << " is already installed.";
+        LOG(ERROR) << "Higher version of Chrome is already installed.";
         int message_id = IDS_INSTALL_HIGHER_VERSION_BASE;
         proceed_with_installation = false;
         install_status = HIGHER_VERSION_EXISTS;
diff --git a/chrome/installer/setup/setup_util.cc b/chrome/installer/setup/setup_util.cc
index 5724c03..72174bd3 100644
--- a/chrome/installer/setup/setup_util.cc
+++ b/chrome/installer/setup/setup_util.cc
@@ -158,18 +158,20 @@
   // ClientState\UninstallString contains a path including "\Chrome Frame\".
   // Multi-install GCF would have had "\Chrome\", and anything else is garbage.
 
-  UpdatingAppRegistrationData gcf_data(
-      L"{8BA986DA-5100-405E-AA35-86F34A02ACBF}");
+  static constexpr wchar_t kGcfGuid[] =
+      L"{8BA986DA-5100-405E-AA35-86F34A02ACBF}";
+  base::string16 clients_key_path = install_static::GetClientsKeyPath(kGcfGuid);
   base::win::RegKey clients_key;
+  base::string16 client_state_key_path =
+      install_static::GetClientStateKeyPath(kGcfGuid);
   base::win::RegKey client_state_key;
 
   const bool has_clients_key =
-      clients_key.Open(installer_state.root_key(),
-                       gcf_data.GetVersionKey().c_str(),
+      clients_key.Open(installer_state.root_key(), clients_key_path.c_str(),
                        KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS;
   const bool has_client_state_key =
       client_state_key.Open(installer_state.root_key(),
-                            gcf_data.GetStateKey().c_str(),
+                            client_state_key_path.c_str(),
                             KEY_QUERY_VALUE | KEY_WOW64_32KEY) == ERROR_SUCCESS;
   if (!has_clients_key && !has_client_state_key)
     return;  // Nothing to check or to clean.
@@ -195,12 +197,11 @@
   int success_count = 0;
 
   if (InstallUtil::DeleteRegistryKey(installer_state.root_key(),
-                                     gcf_data.GetVersionKey(),
-                                     KEY_WOW64_32KEY)) {
+                                     clients_key_path, KEY_WOW64_32KEY)) {
     ++success_count;
   }
   if (InstallUtil::DeleteRegistryKey(installer_state.root_key(),
-                                     gcf_data.GetStateKey(), KEY_WOW64_32KEY)) {
+                                     client_state_key_path, KEY_WOW64_32KEY)) {
     ++success_count;
   }
   if (InstallUtil::DeleteRegistryKey(
@@ -230,10 +231,10 @@
 void RemoveAppLauncherVersionKey(const InstallerState& installer_state) {
 // The app launcher was only registered for Google Chrome.
 #if defined(GOOGLE_CHROME_BUILD)
-  UpdatingAppRegistrationData reg_data(
-      L"{FDA71E6F-AC4C-4a00-8B70-9958A68906BF}");
+  static constexpr wchar_t kLauncherGuid[] =
+      L"{FDA71E6F-AC4C-4a00-8B70-9958A68906BF}";
 
-  base::string16 path(reg_data.GetVersionKey());
+  base::string16 path = install_static::GetClientsKeyPath(kLauncherGuid);
   if (base::win::RegKey(installer_state.root_key(), path.c_str(),
                         KEY_QUERY_VALUE | KEY_WOW64_32KEY)
           .Valid()) {
@@ -261,9 +262,7 @@
 void RemoveLegacyChromeAppCommands(const InstallerState& installer_state) {
 // These app commands were only registered for Google Chrome.
 #if defined(GOOGLE_CHROME_BUILD)
-  base::string16 path(GetRegistrationDataCommandKey(
-      installer_state.product().distribution()->GetAppRegistrationData(),
-      L"install-extension"));
+  base::string16 path(GetCommandKey(L"install-extension"));
 
   if (base::win::RegKey(installer_state.root_key(), path.c_str(),
                         KEY_QUERY_VALUE | KEY_WOW64_32KEY)
@@ -520,10 +519,8 @@
   return base::CPU().has_sse2();
 }
 
-base::string16 GetRegistrationDataCommandKey(
-    const AppRegistrationData& reg_data,
-    const wchar_t* name) {
-  base::string16 cmd_key(reg_data.GetVersionKey());
+base::string16 GetCommandKey(const wchar_t* name) {
+  base::string16 cmd_key = install_static::GetClientsKeyPath();
   cmd_key.append(1, base::FilePath::kSeparators[0])
       .append(google_update::kRegCommandsKey)
       .append(1, base::FilePath::kSeparators[0])
diff --git a/chrome/installer/setup/setup_util.h b/chrome/installer/setup/setup_util.h
index abfe3724..9a46e6a5 100644
--- a/chrome/installer/setup/setup_util.h
+++ b/chrome/installer/setup/setup_util.h
@@ -104,9 +104,7 @@
 bool IsProcessorSupported();
 
 // Returns the "...\\Commands\\|name|" registry key for a product's |reg_data|.
-base::string16 GetRegistrationDataCommandKey(
-    const AppRegistrationData& reg_data,
-    const wchar_t* name);
+base::string16 GetCommandKey(const wchar_t* name);
 
 // Deletes all values and subkeys of the key |path| under |root|, preserving
 // the keys named in |keys_to_preserve| (each of which must be an ASCII string).
diff --git a/chrome/installer/setup/setup_util_unittest.cc b/chrome/installer/setup/setup_util_unittest.cc
index 5192003..ea646ddc 100644
--- a/chrome/installer/setup/setup_util_unittest.cc
+++ b/chrome/installer/setup/setup_util_unittest.cc
@@ -440,11 +440,8 @@
 }
 
 TEST(SetupUtilTest, GetRegistrationDataCommandKey) {
-  base::string16 app_guid = L"{AAAAAAAA-BBBB-1111-0123-456789ABCDEF}";
-  UpdatingAppRegistrationData reg_data(app_guid);
-  base::string16 key =
-      installer::GetRegistrationDataCommandKey(reg_data, L"test_name");
-  EXPECT_TRUE(base::EndsWith(key, app_guid + L"\\Commands\\test_name",
+  const base::string16 key = installer::GetCommandKey(L"test_name");
+  EXPECT_TRUE(base::EndsWith(key, L"\\Commands\\test_name",
                              base::CompareCase::SENSITIVE));
 }
 
diff --git a/chrome/installer/setup/uninstall.cc b/chrome/installer/setup/uninstall.cc
index 3d5eae2..144833e 100644
--- a/chrome/installer/setup/uninstall.cc
+++ b/chrome/installer/setup/uninstall.cc
@@ -161,7 +161,6 @@
     NOTREACHED();
     return;
   }
-  BrowserDistribution* dist = product.distribution();
   ShellUtil::ShellChange install_level = ShellUtil::CURRENT_USER;
 
   // Retarget all shortcuts that point to |old_target_exe| from all
@@ -170,8 +169,8 @@
   for (int location = ShellUtil::SHORTCUT_LOCATION_FIRST;
       location < ShellUtil::NUM_SHORTCUT_LOCATIONS; ++location) {
     if (!ShellUtil::RetargetShortcutsWithArgs(
-            static_cast<ShellUtil::ShortcutLocation>(location), dist,
-            install_level, old_target_exe, new_target_exe)) {
+            static_cast<ShellUtil::ShortcutLocation>(location), install_level,
+            old_target_exe, new_target_exe)) {
       LOG(WARNING) << "Failed to retarget shortcuts in ShortcutLocation: "
                    << location;
     }
@@ -184,8 +183,6 @@
 void DeleteShortcuts(const InstallerState& installer_state,
                      const Product& product,
                      const base::FilePath& target_exe) {
-  BrowserDistribution* dist = product.distribution();
-
   // The per-user shortcut for this user, if present on a system-level install,
   // has already been deleted in chrome_browser_main_win.cc::DoUninstallTasks().
   ShellUtil::ShellChange install_level = installer_state.system_install() ?
@@ -197,8 +194,8 @@
   for (int location = ShellUtil::SHORTCUT_LOCATION_FIRST;
        location < ShellUtil::NUM_SHORTCUT_LOCATIONS; ++location) {
     if (!ShellUtil::RemoveShortcuts(
-            static_cast<ShellUtil::ShortcutLocation>(location), dist,
-            install_level, target_exe)) {
+            static_cast<ShellUtil::ShortcutLocation>(location), install_level,
+            target_exe)) {
       LOG(WARNING) << "Failed to delete shortcuts in ShortcutLocation: "
                    << location;
     }
@@ -792,10 +789,9 @@
   }
 }
 
-void UninstallFirewallRules(BrowserDistribution* dist,
-                            const base::FilePath& chrome_exe) {
+void UninstallFirewallRules(const base::FilePath& chrome_exe) {
   std::unique_ptr<FirewallManager> manager =
-      FirewallManager::Create(dist, chrome_exe);
+      FirewallManager::Create(chrome_exe);
   if (manager)
     manager->RemoveFirewallRules();
 }
@@ -812,7 +808,7 @@
   const base::FilePath chrome_exe(
       installer_state.target_path().Append(installer::kChromeExe));
 
-  VLOG(1) << "UninstallProduct: " << browser_dist->GetDisplayName();
+  VLOG(1) << "UninstallProduct: Chrome";
 
   if (force_uninstall) {
     // Since --force-uninstall command line option is used, we are going to
@@ -883,7 +879,7 @@
   HKEY reg_root = installer_state.root_key();
 
   // Note that we must retrieve the distribution-specific data before deleting
-  // product.GetVersionKey().
+  // the browser's Clients key.
   base::string16 distribution_data(GetDistributionData());
 
   // Remove Control Panel uninstall link.
@@ -894,8 +890,8 @@
       reg_root, install_static::GetUninstallRegistryPath(), KEY_WOW64_32KEY);
 
   // Remove Omaha product key.
-  InstallUtil::DeleteRegistryKey(
-      reg_root, browser_dist->GetVersionKey(), KEY_WOW64_32KEY);
+  InstallUtil::DeleteRegistryKey(reg_root, install_static::GetClientsKeyPath(),
+                                 KEY_WOW64_32KEY);
 
   // Also try to delete the MSI value in the ClientState key (it might not be
   // there). This is due to a Google Update behaviour where an uninstall and a
@@ -963,7 +959,7 @@
 
   UninstallActiveSetupEntries(installer_state);
 
-  UninstallFirewallRules(browser_dist, chrome_exe);
+  UninstallFirewallRules(chrome_exe);
 
   RemoveBlacklistState();
 
diff --git a/chrome/installer/util/app_command.cc b/chrome/installer/util/app_command.cc
index f2fddbc..9b6981d6 100644
--- a/chrome/installer/util/app_command.cc
+++ b/chrome/installer/util/app_command.cc
@@ -74,7 +74,7 @@
                               const base::string16& command_path,
                               WorkItemList* item_list) const {
   // Command_path is derived from GetRegCommandKey which always returns
-  // value from GetVersionKey() which should be 32-bit hive.
+  // value from GetClientsKeyPath() which should be 32-bit hive.
   item_list->AddCreateRegKeyWorkItem(
                  predefined_root, command_path, KEY_WOW64_32KEY)
       ->set_log_message("creating AppCommand registry key");
diff --git a/chrome/installer/util/app_registration_data.h b/chrome/installer/util/app_registration_data.h
index b19ff80..f3e98fa 100644
--- a/chrome/installer/util/app_registration_data.h
+++ b/chrome/installer/util/app_registration_data.h
@@ -14,7 +14,6 @@
   virtual ~AppRegistrationData() {}
   virtual base::string16 GetStateKey() const = 0;
   virtual base::string16 GetStateMediumKey() const = 0;
-  virtual base::string16 GetVersionKey() const = 0;
 };
 
 #endif  // CHROME_INSTALLER_UTIL_APP_REGISTRATION_DATA_H_
diff --git a/chrome/installer/util/browser_distribution.cc b/chrome/installer/util/browser_distribution.cc
index 8d60b8e..c5784b7 100644
--- a/chrome/installer/util/browser_distribution.cc
+++ b/chrome/installer/util/browser_distribution.cc
@@ -12,11 +12,8 @@
 #include <utility>
 
 #include "base/atomicops.h"
-#include "base/logging.h"
 #include "chrome/installer/util/app_registration_data.h"
 #include "chrome/installer/util/google_chrome_distribution.h"
-#include "chrome/installer/util/installer_util_strings.h"
-#include "chrome/installer/util/l10n_string_util.h"
 #include "chrome/installer/util/non_updating_app_registration_data.h"
 
 namespace {
@@ -76,34 +73,3 @@
 base::string16 BrowserDistribution::GetStateMediumKey() const {
   return app_reg_data_->GetStateMediumKey();
 }
-
-base::string16 BrowserDistribution::GetVersionKey() const {
-  return app_reg_data_->GetVersionKey();
-}
-
-base::string16 BrowserDistribution::GetDisplayName() {
-  return GetShortcutName();
-}
-
-base::string16 BrowserDistribution::GetShortcutName() {
-  // IDS_PRODUCT_NAME is automatically mapped to the mode-specific shortcut
-  // name.
-  return installer::GetLocalizedString(IDS_PRODUCT_NAME_BASE);
-}
-
-base::string16 BrowserDistribution::GetStartMenuShortcutSubfolder(
-    Subfolder subfolder_type) {
-  switch (subfolder_type) {
-    case SUBFOLDER_APPS:
-      return installer::GetLocalizedString(IDS_APP_SHORTCUTS_SUBDIR_NAME_BASE);
-    default:
-      DCHECK_EQ(SUBFOLDER_CHROME, subfolder_type);
-      return GetShortcutName();
-  }
-}
-
-base::string16 BrowserDistribution::GetLongAppDescription() {
-  const base::string16& app_description =
-      installer::GetLocalizedString(IDS_PRODUCT_DESCRIPTION_BASE);
-  return app_description;
-}
diff --git a/chrome/installer/util/browser_distribution.h b/chrome/installer/util/browser_distribution.h
index 51cf082b..1ed2a309 100644
--- a/chrome/installer/util/browser_distribution.h
+++ b/chrome/installer/util/browser_distribution.h
@@ -11,17 +11,11 @@
 
 #include "base/macros.h"
 #include "base/strings/string16.h"
-#include "chrome/installer/util/util_constants.h"
 
 class AppRegistrationData;
 
 class BrowserDistribution {
  public:
-  enum Subfolder {
-    SUBFOLDER_CHROME,
-    SUBFOLDER_APPS,
-  };
-
   virtual ~BrowserDistribution();
 
   static BrowserDistribution* GetDistribution();
@@ -30,21 +24,6 @@
   const AppRegistrationData& GetAppRegistrationData() const;
   base::string16 GetStateKey() const;
   base::string16 GetStateMediumKey() const;
-  base::string16 GetVersionKey() const;
-
-  // Returns the localized display name of this distribution.
-  virtual base::string16 GetDisplayName();
-
-  // Returns the localized name of the Chrome shortcut for this distribution.
-  virtual base::string16 GetShortcutName();
-
-  // Returns the localized name of the subfolder in the Start Menu identified by
-  // |subfolder_type| that this distribution should create shortcuts in. For
-  // SUBFOLDER_CHROME this returns GetShortcutName().
-  virtual base::string16 GetStartMenuShortcutSubfolder(
-      Subfolder subfolder_type);
-
-  virtual base::string16 GetLongAppDescription();
 
  protected:
   explicit BrowserDistribution(
diff --git a/chrome/installer/util/firewall_manager_win.cc b/chrome/installer/util/firewall_manager_win.cc
index b57f9952..b791cb9 100644
--- a/chrome/installer/util/firewall_manager_win.cc
+++ b/chrome/installer/util/firewall_manager_win.cc
@@ -12,7 +12,7 @@
 #include "base/macros.h"
 #include "base/strings/string16.h"
 #include "chrome/installer/util/advanced_firewall_manager_win.h"
-#include "chrome/installer/util/browser_distribution.h"
+#include "chrome/installer/util/install_util.h"
 #include "chrome/installer/util/installer_util_strings.h"
 #include "chrome/installer/util/l10n_string_util.h"
 
@@ -65,11 +65,10 @@
 
 // static
 std::unique_ptr<FirewallManager> FirewallManager::Create(
-    BrowserDistribution* dist,
     const base::FilePath& chrome_path) {
   // Try to connect to "Windows Firewall with Advanced Security" (Vista+).
   auto manager = std::make_unique<FirewallManagerAdvancedImpl>();
-  if (manager->Init(dist->GetDisplayName(), chrome_path))
+  if (manager->Init(InstallUtil::GetDisplayName(), chrome_path))
     return std::move(manager);
 
   return nullptr;
diff --git a/chrome/installer/util/firewall_manager_win.h b/chrome/installer/util/firewall_manager_win.h
index 9fe837f..7948dba 100644
--- a/chrome/installer/util/firewall_manager_win.h
+++ b/chrome/installer/util/firewall_manager_win.h
@@ -9,8 +9,6 @@
 
 #include "base/macros.h"
 
-class BrowserDistribution;
-
 namespace base {
 class FilePath;
 }
@@ -25,7 +23,6 @@
   // Creates instance of |FirewallManager|. Implementation chooses best version
   // available for current version of Windows.
   static std::unique_ptr<FirewallManager> Create(
-      BrowserDistribution* dist,
       const base::FilePath& chrome_path);
 
   // Returns true if application can one ports for incoming connections without
diff --git a/chrome/installer/util/google_chrome_distribution_dummy.cc b/chrome/installer/util/google_chrome_distribution_dummy.cc
index 7ef5481..0ec4df4 100644
--- a/chrome/installer/util/google_chrome_distribution_dummy.cc
+++ b/chrome/installer/util/google_chrome_distribution_dummy.cc
@@ -10,45 +10,11 @@
 
 #include "chrome/installer/util/google_chrome_distribution.h"
 
-#include <windows.h>
-
 #include <utility>
 
-#include "base/files/file_path.h"
-#include "base/logging.h"
-#include "base/values.h"
 #include "chrome/installer/util/app_registration_data.h"
 #include "chrome/installer/util/non_updating_app_registration_data.h"
 
 GoogleChromeDistribution::GoogleChromeDistribution()
     : BrowserDistribution(
-          CHROME_BROWSER,
-          std::unique_ptr<AppRegistrationData>(
-              new NonUpdatingAppRegistrationData(base::string16()))) {}
-
-GoogleChromeDistribution::GoogleChromeDistribution(
-    std::unique_ptr<AppRegistrationData> app_reg_data)
-    : BrowserDistribution(CHROME_BROWSER, std::move(app_reg_data)) {}
-
-void GoogleChromeDistribution::DoPostUninstallOperations(
-    const Version& version,
-    const base::FilePath& local_data_path,
-    const base::string16& distribution_data) {
-}
-
-base::string16 GoogleChromeDistribution::GetShortcutName() {
-  return base::string16();
-}
-
-base::string16 GoogleChromeDistribution::GetPublisherName() {
-  return base::string16();
-}
-
-base::string16 GoogleChromeDistribution::GetDistributionData(HKEY root_key) {
-  return base::string16();
-}
-
-void GoogleChromeDistribution::UpdateInstallStatus(bool system_install,
-    installer::ArchiveType archive_type,
-    installer::InstallStatus install_status) {
-}
+          std::make_unique<NonUpdatingAppRegistrationData>(base::string16()));
diff --git a/chrome/installer/util/install_util.cc b/chrome/installer/util/install_util.cc
index 8ca954a4..e12d024 100644
--- a/chrome/installer/util/install_util.cc
+++ b/chrome/installer/util/install_util.cc
@@ -33,7 +33,6 @@
 #include "chrome/install_static/install_details.h"
 #include "chrome/install_static/install_modes.h"
 #include "chrome/install_static/install_util.h"
-#include "chrome/installer/util/browser_distribution.h"
 #include "chrome/installer/util/google_update_constants.h"
 #include "chrome/installer/util/installation_state.h"
 #include "chrome/installer/util/installer_util_strings.h"
@@ -311,20 +310,18 @@
 
 // static
 bool InstallUtil::IsStartMenuShortcutWithActivatorGuidInstalled() {
-  BrowserDistribution* dist = BrowserDistribution::GetDistribution();
   base::FilePath shortcut_path;
 
-  if (!ShellUtil::GetShortcutPath(
-          ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT, dist,
-          install_static::IsSystemInstall() ? ShellUtil::SYSTEM_LEVEL
-                                            : ShellUtil::CURRENT_USER,
-          &shortcut_path)) {
+  if (!ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT,
+                                  install_static::IsSystemInstall()
+                                      ? ShellUtil::SYSTEM_LEVEL
+                                      : ShellUtil::CURRENT_USER,
+                                  &shortcut_path)) {
     LogStartMenuShortcutStatus(StartMenuShortcutStatus::kGetShortcutPathFailed);
     return false;
   }
 
-  shortcut_path =
-      shortcut_path.Append(dist->GetShortcutName() + installer::kLnkExt);
+  shortcut_path = shortcut_path.Append(GetShortcutName() + installer::kLnkExt);
   if (!base::PathExists(shortcut_path)) {
     LogStartMenuShortcutStatus(StartMenuShortcutStatus::kShortcutMissing);
     return false;
@@ -689,6 +686,11 @@
 }
 
 // static
+base::string16 InstallUtil::GetDisplayName() {
+  return GetShortcutName();
+}
+
+// static
 base::string16 InstallUtil::GetAppDescription() {
   return installer::GetLocalizedString(IDS_SHORTCUT_TOOLTIP_BASE);
 }
@@ -698,6 +700,30 @@
   return installer::GetLocalizedString(IDS_ABOUT_VERSION_COMPANY_NAME_BASE);
 }
 
+// static
+base::string16 InstallUtil::GetShortcutName() {
+  // IDS_PRODUCT_NAME is automatically mapped to the mode-specific shortcut
+  // name; see MODE_SPECIFIC_STRINGS in prebuild/create_string_rc.py.
+  return installer::GetLocalizedString(IDS_PRODUCT_NAME_BASE);
+}
+
+// static
+base::string16 InstallUtil::GetChromeShortcutDirNameDeprecated() {
+  return GetShortcutName();
+}
+
+// static
+base::string16 InstallUtil::GetChromeAppsShortcutDirName() {
+  // IDS_APP_SHORTCUTS_SUBDIR_NAME is automatically mapped to the mode-specific
+  // dir name; see MODE_SPECIFIC_STRINGS in prebuild/create_string_rc.py.
+  return installer::GetLocalizedString(IDS_APP_SHORTCUTS_SUBDIR_NAME_BASE);
+}
+
+// static
+base::string16 InstallUtil::GetLongAppDescription() {
+  return installer::GetLocalizedString(IDS_PRODUCT_DESCRIPTION_BASE);
+}
+
 InstallUtil::ProgramCompare::ProgramCompare(const base::FilePath& path_to_match)
     : path_to_match_(path_to_match),
       file_info_() {
diff --git a/chrome/installer/util/install_util.h b/chrome/installer/util/install_util.h
index f98c6735..403585a 100644
--- a/chrome/installer/util/install_util.h
+++ b/chrome/installer/util/install_util.h
@@ -193,12 +193,32 @@
   // be enrolled.
   static std::wstring GetMachineLevelUserCloudPolicyEnrollmentToken();
 
+  // Returns the localized name of the browser.
+  static base::string16 GetDisplayName();
+
   // Returns the app description for shortcuts.
   static base::string16 GetAppDescription();
 
   // Returns the name of the browser's publisher.
   static base::string16 GetPublisherName();
 
+  // Returns the name of Chrome's shortcut in the Start Menu (among other
+  // places).
+  static base::string16 GetShortcutName();
+
+  // Returns the name of the subdirectory in which Chrome's Start Menu shortcut
+  // was once placed. This remains purely to migrate old installs to the new
+  // style.
+  static base::string16 GetChromeShortcutDirNameDeprecated();
+
+  // Returns the name of the subdirectory in the Start Menu in which Chrome
+  // apps' shortcuts are placed.
+  static base::string16 GetChromeAppsShortcutDirName();
+
+  // Returns the long description of Chrome used when registering as a browser
+  // with Windows.
+  static base::string16 GetLongAppDescription();
+
   // A predicate that compares the program portion of a command line with a
   // given file path.  First, the file paths are compared directly.  If they do
   // not match, the filesystem is consulted to determine if the paths reference
diff --git a/chrome/installer/util/installation_state.cc b/chrome/installer/util/installation_state.cc
index 68e548f..a5e92a0 100644
--- a/chrome/installer/util/installation_state.cc
+++ b/chrome/installer/util/installation_state.cc
@@ -9,6 +9,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/version.h"
 #include "base/win/registry.h"
+#include "chrome/install_static/install_util.h"
 #include "chrome/installer/util/browser_distribution.h"
 #include "chrome/installer/util/google_update_constants.h"
 #include "chrome/installer/util/install_util.h"
@@ -20,13 +21,13 @@
 
 // Initializes |commands| from the "Commands" subkey of |version_key|. Returns
 // false if there is no "Commands" subkey or on error.
-bool InitializeCommands(const base::win::RegKey& version_key,
+bool InitializeCommands(const base::win::RegKey& clients_key,
                         AppCommands* commands) {
   static const DWORD kAccess =
       KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_WOW64_32KEY;
   base::win::RegKey commands_key;
 
-  if (commands_key.Open(version_key.Handle(), google_update::kRegCommandsKey,
+  if (commands_key.Open(clients_key.Handle(), google_update::kRegCommandsKey,
                         kAccess) == ERROR_SUCCESS) {
     return commands->Initialize(commands_key, KEY_WOW64_32KEY);
   }
@@ -53,7 +54,7 @@
   static const DWORD kAccess = KEY_QUERY_VALUE | KEY_WOW64_32KEY;
   const BrowserDistribution* distribution =
       BrowserDistribution::GetDistribution();
-  const std::wstring version_key(distribution->GetVersionKey());
+  const std::wstring clients_key(install_static::GetClientsKeyPath());
   const std::wstring state_key(distribution->GetStateKey());
   const HKEY root_key = system_install ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
   base::win::RegKey key;
@@ -62,7 +63,7 @@
   Clear();
 
   // Read from the Clients key.
-  if (key.Open(root_key, version_key.c_str(), kAccess) == ERROR_SUCCESS) {
+  if (key.Open(root_key, clients_key.c_str(), kAccess) == ERROR_SUCCESS) {
     base::string16 version_str;
     if (key.ReadValue(google_update::kRegVersionField,
                       &version_str) == ERROR_SUCCESS) {
diff --git a/chrome/installer/util/non_updating_app_registration_data.cc b/chrome/installer/util/non_updating_app_registration_data.cc
index cfec116..d8f08cc 100644
--- a/chrome/installer/util/non_updating_app_registration_data.cc
+++ b/chrome/installer/util/non_updating_app_registration_data.cc
@@ -16,7 +16,3 @@
 base::string16 NonUpdatingAppRegistrationData::GetStateMediumKey() const {
   return key_path_;
 }
-
-base::string16 NonUpdatingAppRegistrationData::GetVersionKey() const {
-  return key_path_;
-}
diff --git a/chrome/installer/util/non_updating_app_registration_data.h b/chrome/installer/util/non_updating_app_registration_data.h
index d6f4ff8..0d15cce 100644
--- a/chrome/installer/util/non_updating_app_registration_data.h
+++ b/chrome/installer/util/non_updating_app_registration_data.h
@@ -17,7 +17,6 @@
   ~NonUpdatingAppRegistrationData() override;
   base::string16 GetStateKey() const override;
   base::string16 GetStateMediumKey() const override;
-  base::string16 GetVersionKey() const override;
 
  private:
   const base::string16 key_path_;
diff --git a/chrome/installer/util/product_state_unittest.cc b/chrome/installer/util/product_state_unittest.cc
index 1d07b51..2a7d1274 100644
--- a/chrome/installer/util/product_state_unittest.cc
+++ b/chrome/installer/util/product_state_unittest.cc
@@ -7,6 +7,7 @@
 #include "base/test/test_reg_util_win.h"
 #include "base/version.h"
 #include "base/win/registry.h"
+#include "chrome/install_static/install_util.h"
 #include "chrome/installer/util/browser_distribution.h"
 #include "chrome/installer/util/google_update_constants.h"
 #include "chrome/installer/util/installation_state.h"
@@ -40,9 +41,10 @@
       registry_override_manager_.OverrideRegistry(overridden_));
 
   BrowserDistribution* dist = BrowserDistribution::GetDistribution();
-  ASSERT_EQ(ERROR_SUCCESS,
-            clients_.Create(overridden_, dist->GetVersionKey().c_str(),
-                            KEY_ALL_ACCESS | KEY_WOW64_32KEY));
+  ASSERT_EQ(
+      ERROR_SUCCESS,
+      clients_.Create(overridden_, install_static::GetClientsKeyPath().c_str(),
+                      KEY_ALL_ACCESS | KEY_WOW64_32KEY));
   ASSERT_EQ(ERROR_SUCCESS,
             client_state_.Create(overridden_, dist->GetStateKey().c_str(),
                                  KEY_ALL_ACCESS | KEY_WOW64_32KEY));
diff --git a/chrome/installer/util/product_unittest.cc b/chrome/installer/util/product_unittest.cc
index 70942f47..d6940712 100644
--- a/chrome/installer/util/product_unittest.cc
+++ b/chrome/installer/util/product_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/test/test_reg_util_win.h"
 #include "base/version.h"
 #include "chrome/common/chrome_paths.h"
+#include "chrome/install_static/install_util.h"
 #include "chrome/installer/util/browser_distribution.h"
 #include "chrome/installer/util/google_update_constants.h"
 #include "chrome/installer/util/installation_state.h"
@@ -30,7 +31,6 @@
 
   std::unique_ptr<Product> product =
       std::make_unique<Product>(BrowserDistribution::GetDistribution());
-  BrowserDistribution* distribution = product->distribution();
 
   base::FilePath user_data_dir;
   ASSERT_TRUE(base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir));
@@ -53,7 +53,7 @@
     EXPECT_EQ(nullptr, machine_state.GetProductState(system_level));
 
     // Let's pretend chrome is installed.
-    RegKey version_key(root, distribution->GetVersionKey().c_str(),
+    RegKey version_key(root, install_static::GetClientsKeyPath().c_str(),
                        KEY_ALL_ACCESS);
     ASSERT_TRUE(version_key.Valid());
 
diff --git a/chrome/installer/util/shell_util.cc b/chrome/installer/util/shell_util.cc
index c53a0bc..3b1cc90 100644
--- a/chrome/installer/util/shell_util.cc
+++ b/chrome/installer/util/shell_util.cc
@@ -364,7 +364,6 @@
 // register this installation's ProgId and AppId. These entries need to be
 // registered in HKLM prior to Win8.
 void GetChromeProgIdEntries(
-    BrowserDistribution* dist,
     const base::FilePath& chrome_exe,
     const base::string16& suffix,
     std::vector<std::unique_ptr<RegistryEntry>>* entries) {
@@ -384,7 +383,7 @@
 
   // TODO(grt): http://crbug.com/75152 Write a reference to a localized
   // resource for name, description, and company.
-  app_info.application_name = dist->GetDisplayName();
+  app_info.application_name = InstallUtil::GetDisplayName();
   app_info.application_icon_path = chrome_exe;
   app_info.application_icon_index = chrome_icon_index;
   app_info.application_description = InstallUtil::GetAppDescription();
@@ -424,7 +423,6 @@
 // HKLM prior to Win8. If |suffix| is not empty, these entries are guaranteed to
 // be unique on this machine.
 void GetShellIntegrationEntries(
-    BrowserDistribution* dist,
     const base::FilePath& chrome_exe,
     const base::string16& suffix,
     std::vector<std::unique_ptr<RegistryEntry>>* entries) {
@@ -437,8 +435,8 @@
   // Register Chrome's display name.
   // TODO(grt): http://crbug.com/75152 Also set LocalizedString; see
   // http://msdn.microsoft.com/en-us/library/windows/desktop/cc144109(v=VS.85).aspx#registering_the_display_name
-  entries->push_back(std::make_unique<RegistryEntry>(start_menu_entry,
-                                                     dist->GetDisplayName()));
+  entries->push_back(std::make_unique<RegistryEntry>(
+      start_menu_entry, InstallUtil::GetDisplayName()));
   // Register the "open" verb for launching Chrome via the "Internet" link.
   entries->push_back(std::make_unique<RegistryEntry>(
       start_menu_entry + ShellUtil::kRegShellOpen, quoted_exe_path));
@@ -475,11 +473,12 @@
   // resource rather than this.
   entries->push_back(std::make_unique<RegistryEntry>(
       capabilities, ShellUtil::kRegApplicationDescription,
-      dist->GetLongAppDescription()));
+      InstallUtil::GetLongAppDescription()));
   entries->push_back(std::make_unique<RegistryEntry>(
       capabilities, ShellUtil::kRegApplicationIcon, icon_path));
   entries->push_back(std::make_unique<RegistryEntry>(
-      capabilities, ShellUtil::kRegApplicationName, dist->GetDisplayName()));
+      capabilities, ShellUtil::kRegApplicationName,
+      InstallUtil::GetDisplayName()));
 
   entries->push_back(std::make_unique<RegistryEntry>(
       capabilities + L"\\Startmenu", L"StartMenuInternet", reg_app_name));
@@ -661,13 +660,12 @@
 // still impacted by http://crbug.com/144910). This method will keep returning
 // true for affected users (i.e. who have all the registrations, but over both
 // registry roots).
-bool IsChromeRegistered(BrowserDistribution* dist,
-                        const base::FilePath& chrome_exe,
+bool IsChromeRegistered(const base::FilePath& chrome_exe,
                         const base::string16& suffix,
                         uint32_t look_for_in) {
   std::vector<std::unique_ptr<RegistryEntry>> entries;
-  GetChromeProgIdEntries(dist, chrome_exe, suffix, &entries);
-  GetShellIntegrationEntries(dist, chrome_exe, suffix, &entries);
+  GetChromeProgIdEntries(chrome_exe, suffix, &entries);
+  GetShellIntegrationEntries(chrome_exe, suffix, &entries);
   GetChromeAppRegistrationEntries(chrome_exe, suffix, &entries);
   return AreEntriesAsDesired(entries, look_for_in);
 }
@@ -1027,15 +1025,13 @@
 }
 
 // Returns |properties.shortcut_name| if the property is set, otherwise it
-// returns dist->GetShortcutName(). In any case, it makes sure the return value
-// is suffixed with ".lnk".
+// returns InstallUtil::GetShortcutName(). In any case, it makes sure the return
+// value is suffixed with ".lnk".
 base::string16 ExtractShortcutNameFromProperties(
-    BrowserDistribution* dist,
     const ShellUtil::ShortcutProperties& properties) {
-  DCHECK(dist);
   base::string16 shortcut_name = properties.has_shortcut_name()
                                      ? properties.shortcut_name
-                                     : dist->GetShortcutName();
+                                     : InstallUtil::GetShortcutName();
 
   if (!base::EndsWith(shortcut_name, installer::kLnkExt,
                       base::CompareCase::INSENSITIVE_ASCII))
@@ -1414,7 +1410,7 @@
       shortcut_path, updated_properties, base::win::SHORTCUT_UPDATE_EXISTING);
 }
 
-// {|location|, |dist|, |level|} determine |shortcut_folder|.
+// {|location|, |level|} determine |shortcut_folder|.
 // For each shortcut in |shortcut_folder| that match |shortcut_filter|, apply
 // |shortcut_operation|. Returns true if all operations are successful.
 // All intended operations are attempted, even if failures occur.
@@ -1424,7 +1420,6 @@
     const ShortcutFilterCallback& shortcut_filter,
     const ShortcutOperationCallback& shortcut_operation,
     ShellUtil::ShortcutLocation location,
-    BrowserDistribution* dist,
     ShellUtil::ShellChange level,
     const scoped_refptr<ShellUtil::SharedCancellationFlag>& cancel) {
   DCHECK(!shortcut_operation.is_null());
@@ -1436,7 +1431,7 @@
   }
 
   base::FilePath shortcut_folder;
-  if (!ShellUtil::GetShortcutPath(location, dist, level, &shortcut_folder)) {
+  if (!ShellUtil::GetShortcutPath(location, level, &shortcut_folder)) {
     LOG(WARNING) << "Cannot find path at location " << location;
     return false;
   }
@@ -1465,12 +1460,10 @@
   return success;
 }
 
-
-// If the folder specified by {|location|, |dist|, |level|} is empty, remove it.
+// If the folder specified by {|location|, |level|} is empty, remove it.
 // Otherwise do nothing. Returns true on success, including the vacuous case
 // where no deletion occurred because directory is non-empty.
 bool RemoveShortcutFolderIfEmpty(ShellUtil::ShortcutLocation location,
-                                 BrowserDistribution* dist,
                                  ShellUtil::ShellChange level) {
   // Explicitly whitelist locations, since accidental calls can be very harmful.
   if (location !=
@@ -1482,7 +1475,7 @@
   }
 
   base::FilePath shortcut_folder;
-  if (!ShellUtil::GetShortcutPath(location, dist, level, &shortcut_folder)) {
+  if (!ShellUtil::GetShortcutPath(location, level, &shortcut_folder)) {
     LOG(WARNING) << "Cannot find path at location " << location;
     return false;
   }
@@ -1573,12 +1566,8 @@
 }
 
 bool ShellUtil::GetShortcutPath(ShortcutLocation location,
-                                BrowserDistribution* dist,
                                 ShellChange level,
                                 base::FilePath* path) {
-  // Assert that this is only called with the one relevant distribution.
-  // TODO(grt): Remove this when BrowserDistribution goes away.
-  DCHECK_EQ(BrowserDistribution::GetDistribution(), dist);
   DCHECK(path);
   int dir_key = -1;
   base::string16 folder_to_append;
@@ -1599,14 +1588,12 @@
     case SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED:
       dir_key = (level == CURRENT_USER) ? base::DIR_START_MENU :
                                           base::DIR_COMMON_START_MENU;
-      folder_to_append = dist->GetStartMenuShortcutSubfolder(
-          BrowserDistribution::SUBFOLDER_CHROME);
+      folder_to_append = InstallUtil::GetChromeShortcutDirNameDeprecated();
       break;
     case SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR:
       dir_key = (level == CURRENT_USER) ? base::DIR_START_MENU :
                                           base::DIR_COMMON_START_MENU;
-      folder_to_append = dist->GetStartMenuShortcutSubfolder(
-          BrowserDistribution::SUBFOLDER_APPS);
+      folder_to_append = InstallUtil::GetChromeAppsShortcutDirName();
       break;
     case SHORTCUT_LOCATION_TASKBAR_PINS:
       dir_key = base::DIR_TASKBAR_PINS;
@@ -1658,11 +1645,7 @@
 
 bool ShellUtil::MoveExistingShortcut(ShortcutLocation old_location,
                                      ShortcutLocation new_location,
-                                     BrowserDistribution* dist,
                                      const ShortcutProperties& properties) {
-  // Assert that this is only called with the one relevant distribution.
-  // TODO(grt): Remove this when BrowserDistribution goes away.
-  DCHECK_EQ(BrowserDistribution::GetDistribution(), dist);
   // Explicitly whitelist locations to which this is applicable.
   if (old_location != SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED ||
       new_location != SHORTCUT_LOCATION_START_MENU_ROOT) {
@@ -1670,29 +1653,24 @@
     return false;
   }
 
-  base::string16 shortcut_name(
-      ExtractShortcutNameFromProperties(dist, properties));
+  base::string16 shortcut_name(ExtractShortcutNameFromProperties(properties));
 
   base::FilePath old_shortcut_path;
   base::FilePath new_shortcut_path;
-  GetShortcutPath(old_location, dist, properties.level, &old_shortcut_path);
-  GetShortcutPath(new_location, dist, properties.level, &new_shortcut_path);
+  GetShortcutPath(old_location, properties.level, &old_shortcut_path);
+  GetShortcutPath(new_location, properties.level, &new_shortcut_path);
   old_shortcut_path = old_shortcut_path.Append(shortcut_name);
   new_shortcut_path = new_shortcut_path.Append(shortcut_name);
 
   bool result = base::Move(old_shortcut_path, new_shortcut_path);
-  RemoveShortcutFolderIfEmpty(old_location, dist, properties.level);
+  RemoveShortcutFolderIfEmpty(old_location, properties.level);
   return result;
 }
 
 bool ShellUtil::CreateOrUpdateShortcut(
     ShortcutLocation location,
-    BrowserDistribution* dist,
     const ShortcutProperties& properties,
     ShortcutOperation operation) {
-  // Assert that this is only called with the one relevant distribution.
-  // TODO(grt): Remove this when BrowserDistribution goes away.
-  DCHECK_EQ(BrowserDistribution::GetDistribution(), dist);
   // Explicitly whitelist locations to which this is applicable.
   if (location != SHORTCUT_LOCATION_DESKTOP &&
       location != SHORTCUT_LOCATION_QUICK_LAUNCH &&
@@ -1703,7 +1681,6 @@
     return false;
   }
 
-  DCHECK(dist);
   // |pin_to_taskbar| is only acknowledged when first creating the shortcut.
   DCHECK(!properties.pin_to_taskbar ||
          operation == SHELL_SHORTCUT_CREATE_ALWAYS ||
@@ -1714,14 +1691,12 @@
   if (location == SHORTCUT_LOCATION_QUICK_LAUNCH) {
     // There is no system-level shortcut for Quick Launch.
     DCHECK_EQ(properties.level, CURRENT_USER);
-  } else if (!GetShortcutPath(
-                 location, dist, SYSTEM_LEVEL, &system_shortcut_path)) {
+  } else if (!GetShortcutPath(location, SYSTEM_LEVEL, &system_shortcut_path)) {
     NOTREACHED();
     return false;
   }
 
-  base::string16 shortcut_name(
-      ExtractShortcutNameFromProperties(dist, properties));
+  base::string16 shortcut_name(ExtractShortcutNameFromProperties(properties));
   system_shortcut_path = system_shortcut_path.Append(shortcut_name);
 
   base::FilePath* chosen_path;
@@ -1735,7 +1710,7 @@
     // Otherwise install the user-level shortcut, unless the system-level
     // variant of this shortcut is present on the machine and |operation| states
     // not to create a user-level shortcut in that case.
-    if (!GetShortcutPath(location, dist, CURRENT_USER, &user_shortcut_path)) {
+    if (!GetShortcutPath(location, CURRENT_USER, &user_shortcut_path)) {
       NOTREACHED();
       return false;
     }
@@ -2249,7 +2224,7 @@
                                     : RegistryEntry::LOOK_IN_HKLM;
 
   // Check if chrome is already registered with this suffix.
-  if (IsChromeRegistered(dist, chrome_exe, suffix, look_for_in))
+  if (IsChromeRegistered(chrome_exe, suffix, look_for_in))
     return true;
 
   // Ensure that the shell is notified of the mutations below. Specific exit
@@ -2262,11 +2237,10 @@
   if (root == HKEY_CURRENT_USER || IsUserAnAdmin()) {
     std::vector<std::unique_ptr<RegistryEntry>> progid_and_appreg_entries;
     std::vector<std::unique_ptr<RegistryEntry>> shell_entries;
-    GetChromeProgIdEntries(dist, chrome_exe, suffix,
-                           &progid_and_appreg_entries);
+    GetChromeProgIdEntries(chrome_exe, suffix, &progid_and_appreg_entries);
     GetChromeAppRegistrationEntries(chrome_exe, suffix,
                                     &progid_and_appreg_entries);
-    GetShellIntegrationEntries(dist, chrome_exe, suffix, &shell_entries);
+    GetShellIntegrationEntries(chrome_exe, suffix, &shell_entries);
     return AddRegistryEntries(root, progid_and_appreg_entries) &&
            AddRegistryEntries(root, shell_entries);
   }
@@ -2288,7 +2262,7 @@
   // If we got to this point then all we can do is create ProgId and basic app
   // registrations under HKCU.
   std::vector<std::unique_ptr<RegistryEntry>> entries;
-  GetChromeProgIdEntries(dist, chrome_exe, base::string16(), &entries);
+  GetChromeProgIdEntries(chrome_exe, base::string16(), &entries);
   // Prefer to use |suffix|; unless Chrome's ProgIds are already registered with
   // no suffix (as per the old registration style): in which case some other
   // registry entries could refer to them and since we were not able to set our
@@ -2296,7 +2270,7 @@
   if (!AreEntriesAsDesired(entries, RegistryEntry::LOOK_IN_HKCU)) {
     if (!suffix.empty()) {
       entries.clear();
-      GetChromeProgIdEntries(dist, chrome_exe, suffix, &entries);
+      GetChromeProgIdEntries(chrome_exe, suffix, &entries);
       GetChromeAppRegistrationEntries(chrome_exe, suffix, &entries);
     }
     return AddRegistryEntries(HKEY_CURRENT_USER, entries);
@@ -2359,12 +2333,8 @@
 
 // static
 bool ShellUtil::RemoveShortcuts(ShortcutLocation location,
-                                BrowserDistribution* dist,
                                 ShellChange level,
                                 const base::FilePath& target_exe) {
-  // Assert that this is only called with the one relevant distribution.
-  // TODO(grt): Remove this when BrowserDistribution goes away.
-  DCHECK_EQ(BrowserDistribution::GetDistribution(), dist);
   if (!ShortcutLocationIsSupported(location))
     return true;  // Vacuous success.
 
@@ -2374,15 +2344,15 @@
       location == SHORTCUT_LOCATION_TASKBAR_PINS
           ? base::Bind(&ShortcutOpUnpinFromTaskbar)
           : base::Bind(&ShortcutOpDelete));
-  bool success = BatchShortcutAction(shortcut_filter.AsShortcutFilterCallback(),
-                                     shortcut_operation, location, dist, level,
-                                     NULL);
+  bool success =
+      BatchShortcutAction(shortcut_filter.AsShortcutFilterCallback(),
+                          shortcut_operation, location, level, nullptr);
   // Remove chrome-specific shortcut folders if they are now empty.
   if (success &&
       (location == SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED ||
        location == SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR ||
        location == SHORTCUT_LOCATION_APP_SHORTCUTS)) {
-    success = RemoveShortcutFolderIfEmpty(location, dist, level);
+    success = RemoveShortcutFolderIfEmpty(location, level);
   }
   return success;
 }
@@ -2390,13 +2360,9 @@
 // static
 bool ShellUtil::RetargetShortcutsWithArgs(
     ShortcutLocation location,
-    BrowserDistribution* dist,
     ShellChange level,
     const base::FilePath& old_target_exe,
     const base::FilePath& new_target_exe) {
-  // Assert that this is only called with the one relevant distribution.
-  // TODO(grt): Remove this when BrowserDistribution goes away.
-  DCHECK_EQ(BrowserDistribution::GetDistribution(), dist);
   if (!ShortcutLocationIsSupported(location))
     return true;  // Vacuous success.
 
@@ -2404,29 +2370,24 @@
   ShortcutOperationCallback shortcut_operation(
       base::Bind(&ShortcutOpRetarget, old_target_exe, new_target_exe));
   return BatchShortcutAction(shortcut_filter.AsShortcutFilterCallback(),
-                             shortcut_operation, location, dist, level, NULL);
+                             shortcut_operation, location, level, nullptr);
 }
 
 // static
 bool ShellUtil::ShortcutListMaybeRemoveUnknownArgs(
     ShortcutLocation location,
-    BrowserDistribution* dist,
     ShellChange level,
     const base::FilePath& chrome_exe,
     bool do_removal,
     const scoped_refptr<SharedCancellationFlag>& cancel,
     std::vector<std::pair<base::FilePath, base::string16> >* shortcuts) {
-  // Assert that this is only called with the one relevant distribution.
-  // TODO(grt): Remove this when BrowserDistribution goes away.
-  DCHECK_EQ(BrowserDistribution::GetDistribution(), dist);
   if (!ShortcutLocationIsSupported(location))
     return false;
-  DCHECK(dist);
   FilterTargetEq shortcut_filter(chrome_exe, true);
   ShortcutOperationCallback shortcut_operation(
       base::Bind(&ShortcutOpListOrRemoveUnknownArgs, do_removal, shortcuts));
   return BatchShortcutAction(shortcut_filter.AsShortcutFilterCallback(),
-                             shortcut_operation, location, dist, level, cancel);
+                             shortcut_operation, location, level, cancel);
 }
 
 bool ShellUtil::GetUserSpecificRegistrySuffix(base::string16* suffix) {
diff --git a/chrome/installer/util/shell_util.h b/chrome/installer/util/shell_util.h
index 3800405..52dd472 100644
--- a/chrome/installer/util/shell_util.h
+++ b/chrome/installer/util/shell_util.h
@@ -155,7 +155,7 @@
     }
 
     // Forces the shortcut's name to |shortcut_name_in|.
-    // Default: the current distribution's GetShortcutName().
+    // Default: InstallUtil::GetShortcutName().
     // The ".lnk" extension will automatically be added to this name.
     void set_shortcut_name(const base::string16& shortcut_name_in) {
       shortcut_name = shortcut_name_in;
@@ -329,7 +329,6 @@
   // all-users path).
   // Returns false on failure.
   static bool GetShortcutPath(ShortcutLocation location,
-                              BrowserDistribution* dist,
                               ShellChange level,
                               base::FilePath* path);
 
@@ -342,12 +341,10 @@
   // empty, it will be removed.
   static bool MoveExistingShortcut(ShortcutLocation old_location,
                                    ShortcutLocation new_location,
-                                   BrowserDistribution* dist,
                                    const ShortcutProperties& properties);
 
   // Updates shortcut in |location| (or creates it if |options| specify
   // SHELL_SHORTCUT_CREATE_ALWAYS).
-  // |dist| gives the type of browser distribution currently in use.
   // |properties| and |operation| affect this method as described on their
   // invidividual definitions above.
   // |location| may be one of SHORTCUT_LOCATION_DESKTOP,
@@ -356,7 +353,6 @@
   // SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR.
   static bool CreateOrUpdateShortcut(
       ShortcutLocation location,
-      BrowserDistribution* dist,
       const ShortcutProperties& properties,
       ShortcutOperation operation);
 
@@ -377,9 +373,9 @@
   static base::string16 GetChromeDelegateCommand(
       const base::FilePath& chrome_exe);
 
-  // Gets a mapping of all registered browser names (excluding browsers in the
-  // |dist| distribution) and their reinstall command (which usually sets
-  // browser as default).
+  // Gets a mapping of all registered browser names (excluding the current
+  // browser) and their reinstall command (which usually sets browser as
+  // default).
   // Given browsers can be registered in HKCU (as of Win7) and/or in HKLM, this
   // method looks in both and gives precedence to values in HKCU as per the msdn
   // standard: http://goo.gl/xjczJ.
@@ -576,7 +572,6 @@
   // Returns true if all shortcuts pointing to |target_exe| are successfully
   // deleted, including the case where no such shortcuts are found.
   static bool RemoveShortcuts(ShortcutLocation location,
-                              BrowserDistribution* dist,
                               ShellChange level,
                               const base::FilePath& target_exe);
 
@@ -590,7 +585,6 @@
   // the vacuous case where no matching shortcuts are found.
   static bool RetargetShortcutsWithArgs(
       ShortcutLocation location,
-      BrowserDistribution* dist,
       ShellChange level,
       const base::FilePath& old_target_exe,
       const base::FilePath& new_target_exe);
@@ -603,7 +597,6 @@
   // non-NULL and gets set at any point during this call.
   static bool ShortcutListMaybeRemoveUnknownArgs(
       ShortcutLocation location,
-      BrowserDistribution* dist,
       ShellChange level,
       const base::FilePath& chrome_exe,
       bool do_removal,
diff --git a/chrome/installer/util/shell_util_unittest.cc b/chrome/installer/util/shell_util_unittest.cc
index 8934ab8..a2bc7f3 100644
--- a/chrome/installer/util/shell_util_unittest.cc
+++ b/chrome/installer/util/shell_util_unittest.cc
@@ -29,7 +29,6 @@
 #include "base/win/shortcut.h"
 #include "base/win/windows_version.h"
 #include "chrome/install_static/install_util.h"
-#include "chrome/installer/util/browser_distribution.h"
 #include "chrome/installer/util/install_util.h"
 #include "chrome/installer/util/util_constants.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -58,9 +57,6 @@
   ShellUtilShortcutTest() : test_properties_(ShellUtil::CURRENT_USER) {}
 
   void SetUp() override {
-    dist_ = BrowserDistribution::GetDistribution();
-    ASSERT_TRUE(dist_ != NULL);
-
     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
     chrome_exe_ = temp_dir_.GetPath().Append(installer::kChromeExe);
     EXPECT_EQ(0, base::WriteFile(chrome_exe_, "", 0));
@@ -112,7 +108,6 @@
   // failure.
   base::FilePath GetExpectedShortcutPath(
       ShellUtil::ShortcutLocation location,
-      BrowserDistribution* dist,
       const ShellUtil::ShortcutProperties& properties) {
     base::FilePath expected_path;
     switch (location) {
@@ -134,8 +129,7 @@
                             ? fake_start_menu_.GetPath()
                             : fake_common_start_menu_.GetPath();
         expected_path = expected_path.Append(
-            dist_->GetStartMenuShortcutSubfolder(
-                BrowserDistribution::SUBFOLDER_CHROME));
+            InstallUtil::GetChromeShortcutDirNameDeprecated());
         break;
       default:
         ADD_FAILURE() << "Unknown location";
@@ -144,7 +138,7 @@
 
     base::string16 shortcut_name = properties.has_shortcut_name()
                                        ? properties.shortcut_name
-                                       : dist_->GetShortcutName();
+                                       : InstallUtil::GetShortcutName();
     shortcut_name.append(installer::kLnkExt);
     return expected_path.Append(shortcut_name);
   }
@@ -155,10 +149,8 @@
   // implies real (non-mocked) state which is flaky to test.
   void ValidateChromeShortcut(
       ShellUtil::ShortcutLocation location,
-      BrowserDistribution* dist,
       const ShellUtil::ShortcutProperties& properties) {
-    base::FilePath expected_path(
-        GetExpectedShortcutPath(location, dist, properties));
+    base::FilePath expected_path(GetExpectedShortcutPath(location, properties));
 
     base::win::ShortcutProperties expected_properties;
     if (properties.has_target()) {
@@ -203,8 +195,6 @@
     base::win::ValidateShortcut(expected_path, expected_properties);
   }
 
-  BrowserDistribution* dist_;
-
   // A ShellUtil::ShortcutProperties object with common properties set already.
   ShellUtil::ShortcutProperties test_properties_;
 
@@ -232,29 +222,28 @@
 TEST_F(ShellUtilShortcutTest, GetShortcutPath) {
   base::FilePath path;
 
-  ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
+  ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
                              ShellUtil::CURRENT_USER, &path);
   EXPECT_EQ(fake_user_desktop_.GetPath(), path);
 
-  ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
+  ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
                              ShellUtil::SYSTEM_LEVEL, &path);
   EXPECT_EQ(fake_common_desktop_.GetPath(), path);
 
-  ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, dist_,
+  ShellUtil::GetShortcutPath(ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH,
                              ShellUtil::CURRENT_USER, &path);
   EXPECT_EQ(fake_user_quick_launch_.GetPath(), path);
 
   base::string16 start_menu_subfolder =
-      dist_->GetStartMenuShortcutSubfolder(
-          BrowserDistribution::SUBFOLDER_CHROME);
+      InstallUtil::GetChromeShortcutDirNameDeprecated();
   ShellUtil::GetShortcutPath(
       ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
-      dist_, ShellUtil::CURRENT_USER, &path);
+      ShellUtil::CURRENT_USER, &path);
   EXPECT_EQ(fake_start_menu_.GetPath().Append(start_menu_subfolder), path);
 
   ShellUtil::GetShortcutPath(
       ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
-      dist_, ShellUtil::SYSTEM_LEVEL, &path);
+      ShellUtil::SYSTEM_LEVEL, &path);
   EXPECT_EQ(fake_common_start_menu_.GetPath().Append(start_menu_subfolder),
             path);
 }
@@ -264,28 +253,23 @@
   test_properties_.level = ShellUtil::SYSTEM_LEVEL;
   base::FilePath old_shortcut_path(GetExpectedShortcutPath(
       ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
-      dist_, test_properties_));
+      test_properties_));
 
-  ASSERT_TRUE(
-    ShellUtil::CreateOrUpdateShortcut(
-        ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
-        dist_, test_properties_,
-        ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
+      ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
+      test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   ValidateChromeShortcut(
       ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
-      dist_, test_properties_);
+      test_properties_);
   ASSERT_TRUE(base::PathExists(old_shortcut_path.DirName()));
   ASSERT_TRUE(base::PathExists(old_shortcut_path));
 
-  ASSERT_TRUE(
-    ShellUtil::MoveExistingShortcut(
-        ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
-        ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT,
-        dist_, test_properties_));
+  ASSERT_TRUE(ShellUtil::MoveExistingShortcut(
+      ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
+      ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT, test_properties_));
 
-  ValidateChromeShortcut(
-      ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT,
-      dist_, test_properties_);
+  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT,
+                         test_properties_);
   ASSERT_FALSE(base::PathExists(old_shortcut_path));
   ASSERT_FALSE(base::PathExists(old_shortcut_path.DirName()));
 }
@@ -294,138 +278,131 @@
   ShellUtil::ShortcutProperties properties(ShellUtil::CURRENT_USER);
   ShellUtil::AddDefaultShortcutProperties(chrome_exe_, &properties);
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, properties,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
-  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
-                         properties);
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, properties,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, properties);
 }
 
 TEST_F(ShellUtilShortcutTest, CreateStartMenuShortcutWithAllProperties) {
   test_properties_.set_shortcut_name(L"Bobo le shortcut");
   test_properties_.level = ShellUtil::SYSTEM_LEVEL;
-  ASSERT_TRUE(
-    ShellUtil::CreateOrUpdateShortcut(
-        ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
-        dist_, test_properties_,
-        ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+  ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
+      ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
+      test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   ValidateChromeShortcut(
       ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
-      dist_, test_properties_);
+      test_properties_);
 }
 
 TEST_F(ShellUtilShortcutTest, ReplaceSystemLevelDesktopShortcut) {
   test_properties_.level = ShellUtil::SYSTEM_LEVEL;
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP,
-                  dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
 
   ShellUtil::ShortcutProperties new_properties(ShellUtil::SYSTEM_LEVEL);
   ShellUtil::AddDefaultShortcutProperties(chrome_exe_, &new_properties);
   new_properties.set_description(L"New description");
   new_properties.set_arguments(L"--new-arguments");
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP,
-                  dist_, new_properties,
-                  ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, new_properties,
+      ShellUtil::SHELL_SHORTCUT_REPLACE_EXISTING));
 
   // Expect the properties set in |new_properties| to be set as above and
   // properties that don't have a default value to be set back to their default
   // (as validated in ValidateChromeShortcut()) or unset if they don't .
   ShellUtil::ShortcutProperties expected_properties(new_properties);
 
-  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
+  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
                          expected_properties);
 }
 
 TEST_F(ShellUtilShortcutTest, UpdateQuickLaunchShortcutArguments) {
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH,
-                  dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
 
   // Only changing one property, don't need all the defaults.
   ShellUtil::ShortcutProperties updated_properties(ShellUtil::CURRENT_USER);
   updated_properties.set_arguments(L"--updated --arguments");
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH,
-                  dist_, updated_properties,
-                  ShellUtil::SHELL_SHORTCUT_UPDATE_EXISTING));
+      ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, updated_properties,
+      ShellUtil::SHELL_SHORTCUT_UPDATE_EXISTING));
 
   // Expect the properties set in |updated_properties| to be set as above and
   // all other properties to remain unchanged.
   ShellUtil::ShortcutProperties expected_properties(test_properties_);
   expected_properties.set_arguments(updated_properties.arguments);
 
-  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH, dist_,
+  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_QUICK_LAUNCH,
                          expected_properties);
 }
 
 TEST_F(ShellUtilShortcutTest, CreateIfNoSystemLevel) {
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL));
-  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL));
+  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
                          test_properties_);
 }
 
 TEST_F(ShellUtilShortcutTest, CreateIfNoSystemLevelWithSystemLevelPresent) {
-  base::string16 shortcut_name(dist_->GetShortcutName() + installer::kLnkExt);
+  base::string16 shortcut_name(InstallUtil::GetShortcutName() +
+                               installer::kLnkExt);
 
   test_properties_.level = ShellUtil::SYSTEM_LEVEL;
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   ASSERT_TRUE(
       base::PathExists(fake_common_desktop_.GetPath().Append(shortcut_name)));
 
   test_properties_.level = ShellUtil::CURRENT_USER;
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL));
   ASSERT_FALSE(
       base::PathExists(fake_user_desktop_.GetPath().Append(shortcut_name)));
 }
 
 TEST_F(ShellUtilShortcutTest, CreateIfNoSystemLevelStartMenu) {
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
-                  dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL));
+      ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
+      test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_IF_NO_SYSTEM_LEVEL));
   ValidateChromeShortcut(
       ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
-      dist_, test_properties_);
+      test_properties_);
 }
 
 TEST_F(ShellUtilShortcutTest, CreateAlwaysUserWithSystemLevelPresent) {
-  base::string16 shortcut_name(dist_->GetShortcutName() + installer::kLnkExt);
+  base::string16 shortcut_name(InstallUtil::GetShortcutName() +
+                               installer::kLnkExt);
 
   test_properties_.level = ShellUtil::SYSTEM_LEVEL;
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   ASSERT_TRUE(
       base::PathExists(fake_common_desktop_.GetPath().Append(shortcut_name)));
 
   test_properties_.level = ShellUtil::CURRENT_USER;
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   ASSERT_TRUE(
       base::PathExists(fake_user_desktop_.GetPath().Append(shortcut_name)));
 }
 
 TEST_F(ShellUtilShortcutTest, RemoveChromeShortcut) {
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   base::FilePath shortcut_path = GetExpectedShortcutPath(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_);
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_);
   ASSERT_TRUE(base::PathExists(shortcut_path));
 
-  ASSERT_TRUE(ShellUtil::RemoveShortcuts(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER,
-      chrome_exe_));
+  ASSERT_TRUE(ShellUtil::RemoveShortcuts(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
+                                         ShellUtil::CURRENT_USER, chrome_exe_));
   ASSERT_FALSE(base::PathExists(shortcut_path));
   ASSERT_TRUE(base::PathExists(shortcut_path.DirName()));
 }
@@ -433,15 +410,14 @@
 TEST_F(ShellUtilShortcutTest, RemoveSystemLevelChromeShortcut) {
   test_properties_.level = ShellUtil::SYSTEM_LEVEL;
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   base::FilePath shortcut_path = GetExpectedShortcutPath(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_);
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_);
   ASSERT_TRUE(base::PathExists(shortcut_path));
 
-  ASSERT_TRUE(ShellUtil::RemoveShortcuts(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::SYSTEM_LEVEL,
-      chrome_exe_));
+  ASSERT_TRUE(ShellUtil::RemoveShortcuts(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
+                                         ShellUtil::SYSTEM_LEVEL, chrome_exe_));
   ASSERT_FALSE(base::PathExists(shortcut_path));
   ASSERT_TRUE(base::PathExists(shortcut_path.DirName()));
 }
@@ -451,10 +427,10 @@
   test_properties_.set_shortcut_name(L"Chrome 1");
   test_properties_.set_arguments(L"");
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   base::FilePath shortcut1_path = GetExpectedShortcutPath(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_);
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_);
   ASSERT_TRUE(base::PathExists(shortcut1_path));
 
   // Shortcut 2: targets "chrome.exe"; has arguments; icon set to "other.ico".
@@ -462,10 +438,10 @@
   test_properties_.set_arguments(L"--profile-directory=\"Profile 2\"");
   test_properties_.set_icon(other_ico_, 0);
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   base::FilePath shortcut2_path = GetExpectedShortcutPath(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_);
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_);
   ASSERT_TRUE(base::PathExists(shortcut2_path));
 
   // Shortcut 3: targets "iron.exe"; has arguments; icon set to "chrome.exe".
@@ -473,16 +449,15 @@
   test_properties_.set_target(iron_exe_);
   test_properties_.set_icon(chrome_exe_, 3);
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   base::FilePath shortcut3_path = GetExpectedShortcutPath(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_);
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_);
   ASSERT_TRUE(base::PathExists(shortcut3_path));
 
   // Remove shortcuts that target "chrome.exe".
-  ASSERT_TRUE(ShellUtil::RemoveShortcuts(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER,
-      chrome_exe_));
+  ASSERT_TRUE(ShellUtil::RemoveShortcuts(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
+                                         ShellUtil::CURRENT_USER, chrome_exe_));
   ASSERT_FALSE(base::PathExists(shortcut1_path));
   ASSERT_FALSE(base::PathExists(shortcut2_path));
   ASSERT_TRUE(base::PathExists(shortcut3_path));
@@ -491,40 +466,40 @@
 
 TEST_F(ShellUtilShortcutTest, RetargetShortcutsWithArgs) {
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   ASSERT_TRUE(base::PathExists(GetExpectedShortcutPath(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_)));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_)));
 
   base::FilePath new_exe = manganese_exe_;
   // Relies on the fact that |test_properties_| has non-empty arguments.
   ASSERT_TRUE(ShellUtil::RetargetShortcutsWithArgs(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER,
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, ShellUtil::CURRENT_USER,
       chrome_exe_, new_exe));
 
   ShellUtil::ShortcutProperties expected_properties(test_properties_);
   expected_properties.set_target(new_exe);
-  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
+  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
                          expected_properties);
 }
 
 TEST_F(ShellUtilShortcutTest, RetargetSystemLevelChromeShortcutsWithArgs) {
   test_properties_.level = ShellUtil::SYSTEM_LEVEL;
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   ASSERT_TRUE(base::PathExists(GetExpectedShortcutPath(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_)));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_)));
 
   base::FilePath new_exe = manganese_exe_;
   // Relies on the fact that |test_properties_| has non-empty arguments.
   ASSERT_TRUE(ShellUtil::RetargetShortcutsWithArgs(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::SYSTEM_LEVEL,
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, ShellUtil::SYSTEM_LEVEL,
       chrome_exe_, new_exe));
 
   ShellUtil::ShortcutProperties expected_properties(test_properties_);
   expected_properties.set_target(new_exe);
-  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
+  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
                          expected_properties);
 }
 
@@ -533,36 +508,36 @@
   test_properties_.set_shortcut_name(L"Chrome 1");
   test_properties_.set_arguments(L"");
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   ASSERT_TRUE(base::PathExists(GetExpectedShortcutPath(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_)));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_)));
   ShellUtil::ShortcutProperties expected_properties1(test_properties_);
 
   // Shortcut 2: targets "chrome.exe"; has arguments.
   test_properties_.set_shortcut_name(L"Chrome 2");
   test_properties_.set_arguments(L"--profile-directory=\"Profile 2\"");
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   ASSERT_TRUE(base::PathExists(GetExpectedShortcutPath(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_)));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_)));
   ShellUtil::ShortcutProperties expected_properties2(test_properties_);
 
   // Retarget shortcuts: replace "chrome.exe" with "manganese.exe". Only
   // shortcuts with non-empty arguments (i.e., shortcut 2) gets updated.
   base::FilePath new_exe = manganese_exe_;
   ASSERT_TRUE(ShellUtil::RetargetShortcutsWithArgs(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER,
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, ShellUtil::CURRENT_USER,
       chrome_exe_, new_exe));
 
   // Verify shortcut 1: no change.
-  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
+  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
                          expected_properties1);
 
   // Verify shortcut 2: target => "manganese.exe".
   expected_properties2.set_target(new_exe);
-  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
+  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
                          expected_properties2);
 }
 
@@ -575,20 +550,20 @@
   test_properties_.set_shortcut_name(L"Chrome 1");
   test_properties_.set_icon(test_properties_.target, kTestIconIndex1);
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   ASSERT_TRUE(base::PathExists(GetExpectedShortcutPath(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_)));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_)));
   ShellUtil::ShortcutProperties expected_properties1(test_properties_);
 
   // Shortcut 2: targets "chrome.exe"; icon set to "other.ico".
   test_properties_.set_shortcut_name(L"Chrome 2");
   test_properties_.set_icon(other_ico_, kTestIconIndex2);
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   ASSERT_TRUE(base::PathExists(GetExpectedShortcutPath(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_)));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_)));
   ShellUtil::ShortcutProperties expected_properties2(test_properties_);
 
   // Shortcut 3: targets "iron.exe"; icon set to "chrome.exe".
@@ -596,32 +571,32 @@
   test_properties_.set_shortcut_name(L"Iron 3");
   test_properties_.set_icon(chrome_exe_, kTestIconIndex3);
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   ASSERT_TRUE(base::PathExists(GetExpectedShortcutPath(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_)));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_)));
   ShellUtil::ShortcutProperties expected_properties3(test_properties_);
 
   // Retarget shortcuts: replace "chrome.exe" with "manganese.exe".
   // Relies on the fact that |test_properties_| has non-empty arguments.
   base::FilePath new_exe = manganese_exe_;
   ASSERT_TRUE(ShellUtil::RetargetShortcutsWithArgs(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER,
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, ShellUtil::CURRENT_USER,
       chrome_exe_, new_exe));
 
   // Verify shortcut 1: target & icon => "manganese.exe", kept same icon index.
   expected_properties1.set_target(new_exe);
   expected_properties1.set_icon(new_exe, kTestIconIndex1);
-  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
+  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
                          expected_properties1);
 
   // Verify shortcut 2: target => "manganese.exe", kept icon.
   expected_properties2.set_target(new_exe);
-  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
+  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
                          expected_properties2);
 
   // Verify shortcut 3: no change, since target doesn't match.
-  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
+  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
                          expected_properties3);
 }
 
@@ -630,10 +605,10 @@
   test_properties_.set_shortcut_name(L"Chrome 1");
   test_properties_.set_arguments(L"");
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   base::FilePath shortcut1_path = GetExpectedShortcutPath(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_);
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_);
   ASSERT_TRUE(base::PathExists(shortcut1_path));
   ShellUtil::ShortcutProperties expected_properties1(test_properties_);
 
@@ -641,10 +616,10 @@
   test_properties_.set_shortcut_name(L"Chrome 2");
   test_properties_.set_arguments(L"--profile-directory=\"Profile 2\"");
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   base::FilePath shortcut2_path = GetExpectedShortcutPath(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_);
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_);
   ASSERT_TRUE(base::PathExists(shortcut2_path));
   ShellUtil::ShortcutProperties expected_properties2(test_properties_);
 
@@ -652,10 +627,10 @@
   test_properties_.set_shortcut_name(L"Chrome 3");
   test_properties_.set_arguments(L"foo.com");
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   base::FilePath shortcut3_path = GetExpectedShortcutPath(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_);
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_);
   ASSERT_TRUE(base::PathExists(shortcut3_path));
   ShellUtil::ShortcutProperties expected_properties3(test_properties_);
 
@@ -663,10 +638,10 @@
   test_properties_.set_shortcut_name(L"Chrome 4");
   test_properties_.set_arguments(L"foo.com --show-app-list");
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   base::FilePath shortcut4_path = GetExpectedShortcutPath(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_);
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_);
   ASSERT_TRUE(base::PathExists(shortcut4_path));
   ShellUtil::ShortcutProperties expected_properties4(test_properties_);
 
@@ -674,7 +649,6 @@
   std::vector<std::pair<base::FilePath, base::string16> > shortcuts;
   EXPECT_TRUE(ShellUtil::ShortcutListMaybeRemoveUnknownArgs(
       ShellUtil::SHORTCUT_LOCATION_DESKTOP,
-      dist_,
       ShellUtil::CURRENT_USER,
       chrome_exe_,
       false,
@@ -694,7 +668,6 @@
   shortcuts.clear();
   EXPECT_TRUE(ShellUtil::ShortcutListMaybeRemoveUnknownArgs(
       ShellUtil::SHORTCUT_LOCATION_DESKTOP,
-      dist_,
       ShellUtil::CURRENT_USER,
       chrome_exe_,
       true,
@@ -710,43 +683,37 @@
   EXPECT_EQ(shortcut4_path, shortcut4.first);
   EXPECT_EQ(L"foo.com --show-app-list", shortcut4.second);
 
-  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
+  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
                          expected_properties1);
-  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
+  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
                          expected_properties2);
   expected_properties3.set_arguments(base::string16());
-  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
+  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
                          expected_properties3);
   expected_properties4.set_arguments(L"--show-app-list");
-  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_,
+  ValidateChromeShortcut(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
                          expected_properties4);
 }
 
 TEST_F(ShellUtilShortcutTest, CreateMultipleStartMenuShortcutsAndRemoveFolder) {
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
-                  dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
+      test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR,
-                  dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   test_properties_.set_shortcut_name(L"A second shortcut");
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
-                  dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
+      test_properties_, ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR,
-                  dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
 
-  base::FilePath chrome_shortcut_folder(
-      fake_start_menu_.GetPath().Append(dist_->GetStartMenuShortcutSubfolder(
-          BrowserDistribution::SUBFOLDER_CHROME)));
-  base::FilePath chrome_apps_shortcut_folder(
-      fake_start_menu_.GetPath().Append(dist_->GetStartMenuShortcutSubfolder(
-          BrowserDistribution::SUBFOLDER_APPS)));
+  base::FilePath chrome_shortcut_folder(fake_start_menu_.GetPath().Append(
+      InstallUtil::GetChromeShortcutDirNameDeprecated()));
+  base::FilePath chrome_apps_shortcut_folder(fake_start_menu_.GetPath().Append(
+      InstallUtil::GetChromeAppsShortcutDirName()));
 
   base::FileEnumerator chrome_file_counter(chrome_shortcut_folder, false,
                                            base::FileEnumerator::FILES);
@@ -765,13 +732,13 @@
 
   ASSERT_TRUE(base::PathExists(chrome_shortcut_folder));
   ASSERT_TRUE(ShellUtil::RemoveShortcuts(
-      ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED, dist_,
+      ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_DIR_DEPRECATED,
       ShellUtil::CURRENT_USER, chrome_exe_));
   ASSERT_FALSE(base::PathExists(chrome_shortcut_folder));
 
   ASSERT_TRUE(base::PathExists(chrome_apps_shortcut_folder));
   ASSERT_TRUE(ShellUtil::RemoveShortcuts(
-      ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR, dist_,
+      ShellUtil::SHORTCUT_LOCATION_START_MENU_CHROME_APPS_DIR,
       ShellUtil::CURRENT_USER, chrome_exe_));
   ASSERT_FALSE(base::PathExists(chrome_apps_shortcut_folder));
 }
@@ -779,19 +746,19 @@
 TEST_F(ShellUtilShortcutTest,
        DeleteStartMenuRootShortcutWithoutRemovingFolder) {
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT,
-                  dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
 
-  base::string16 shortcut_name(dist_->GetShortcutName() + installer::kLnkExt);
+  base::string16 shortcut_name(InstallUtil::GetShortcutName() +
+                               installer::kLnkExt);
   base::FilePath shortcut_path(
       fake_start_menu_.GetPath().Append(shortcut_name));
 
   ASSERT_TRUE(base::PathExists(fake_start_menu_.GetPath()));
   ASSERT_TRUE(base::PathExists(shortcut_path));
-  ASSERT_TRUE(ShellUtil::RemoveShortcuts(
-      ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT, dist_,
-      ShellUtil::CURRENT_USER, chrome_exe_));
+  ASSERT_TRUE(
+      ShellUtil::RemoveShortcuts(ShellUtil::SHORTCUT_LOCATION_START_MENU_ROOT,
+                                 ShellUtil::CURRENT_USER, chrome_exe_));
   // The shortcut should be removed but the "Start Menu" root directory should
   // remain.
   ASSERT_TRUE(base::PathExists(fake_start_menu_.GetPath()));
@@ -807,10 +774,11 @@
 
   test_properties_.set_target(other_chrome_exe);
   ASSERT_TRUE(ShellUtil::CreateOrUpdateShortcut(
-                  ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, test_properties_,
-                  ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
+      ShellUtil::SHORTCUT_LOCATION_DESKTOP, test_properties_,
+      ShellUtil::SHELL_SHORTCUT_CREATE_ALWAYS));
 
-  base::string16 shortcut_name(dist_->GetShortcutName() + installer::kLnkExt);
+  base::string16 shortcut_name(InstallUtil::GetShortcutName() +
+                               installer::kLnkExt);
   base::FilePath shortcut_path(
       fake_user_desktop_.GetPath().Append(shortcut_name));
   ASSERT_TRUE(base::PathExists(shortcut_path));
@@ -818,9 +786,8 @@
   // The shortcut shouldn't be removed as it was installed pointing to
   // |other_chrome_exe| and RemoveChromeShortcut() is being told that the
   // removed shortcut should point to |chrome_exe_|.
-  ASSERT_TRUE(ShellUtil::RemoveShortcuts(
-      ShellUtil::SHORTCUT_LOCATION_DESKTOP, dist_, ShellUtil::CURRENT_USER,
-      chrome_exe_));
+  ASSERT_TRUE(ShellUtil::RemoveShortcuts(ShellUtil::SHORTCUT_LOCATION_DESKTOP,
+                                         ShellUtil::CURRENT_USER, chrome_exe_));
   ASSERT_TRUE(base::PathExists(shortcut_path));
   ASSERT_TRUE(base::PathExists(shortcut_path.DirName()));
 }
diff --git a/chrome/installer/util/test_app_registration_data.cc b/chrome/installer/util/test_app_registration_data.cc
index 79b9807..3dd385f1 100644
--- a/chrome/installer/util/test_app_registration_data.cc
+++ b/chrome/installer/util/test_app_registration_data.cc
@@ -17,7 +17,3 @@
 base::string16 TestAppRegistrationData::GetStateMediumKey() const {
   return L"Software\\Chromium\\ClientStateMedium\\test_app_guid";
 }
-
-base::string16 TestAppRegistrationData::GetVersionKey() const {
-  return L"Software\\Chromium\\Clients\\test_app_guid";
-}
diff --git a/chrome/installer/util/test_app_registration_data.h b/chrome/installer/util/test_app_registration_data.h
index 364f845..99d9ac9d 100644
--- a/chrome/installer/util/test_app_registration_data.h
+++ b/chrome/installer/util/test_app_registration_data.h
@@ -13,7 +13,6 @@
   ~TestAppRegistrationData() override;
   base::string16 GetStateKey() const override;
   base::string16 GetStateMediumKey() const override;
-  base::string16 GetVersionKey() const override;
 };
 
 #endif  // CHROME_INSTALLER_UTIL_TEST_APP_REGISTRATION_DATA_H_
diff --git a/chrome/installer/util/updating_app_registration_data.cc b/chrome/installer/util/updating_app_registration_data.cc
index c9722a24..6416d92 100644
--- a/chrome/installer/util/updating_app_registration_data.cc
+++ b/chrome/installer/util/updating_app_registration_data.cc
@@ -22,9 +22,3 @@
       .append(1, L'\\')
       .append(app_guid_);
 }
-
-base::string16 UpdatingAppRegistrationData::GetVersionKey() const {
-  return base::string16(google_update::kRegPathClients)
-      .append(1, L'\\')
-      .append(app_guid_);
-}
diff --git a/chrome/installer/util/updating_app_registration_data.h b/chrome/installer/util/updating_app_registration_data.h
index e7ac94f..55d1ce2d 100644
--- a/chrome/installer/util/updating_app_registration_data.h
+++ b/chrome/installer/util/updating_app_registration_data.h
@@ -17,7 +17,6 @@
   ~UpdatingAppRegistrationData() override;
   base::string16 GetStateKey() const override;
   base::string16 GetStateMediumKey() const override;
-  base::string16 GetVersionKey() const override;
 
  private:
   const base::string16 app_guid_;
diff --git a/chrome/renderer/resources/extensions/media_router_bindings.js b/chrome/renderer/resources/extensions/media_router_bindings.js
index f6c05b8..bde1e21 100644
--- a/chrome/renderer/resources/extensions/media_router_bindings.js
+++ b/chrome/renderer/resources/extensions/media_router_bindings.js
@@ -1020,6 +1020,17 @@
 }
 
 /**
+ * @param {!url.mojom.Url} presentation_url
+ * @param {!string} presentation_id
+ * @param {!mojo.InterfaceRequest} request
+ */
+MediaRouter.prototype.getMirroringServiceHostForOffscreenTab = function(
+    presentation_url, presentation_id, request) {
+  this.service_.getMirroringServiceHostForOffscreenTab(presentation_url,
+      presentation_id, request);
+}
+
+/**
  * Object containing callbacks set by the provider manager.
  *
  * @constructor
diff --git a/chrome/test/chromedriver/test/run_py_tests.py b/chrome/test/chromedriver/test/run_py_tests.py
index 79ed9d9..7c6a48c 100755
--- a/chrome/test/chromedriver/test/run_py_tests.py
+++ b/chrome/test/chromedriver/test/run_py_tests.py
@@ -88,6 +88,8 @@
     'ChromeDriverTest.testHoverOverElement',
     # https://bugs.chromium.org/p/chromedriver/issues/detail?id=833
     'ChromeDriverTest.testAlertOnNewWindow',
+    # https://bugs.chromium.org/p/chromedriver/issues/detail?id=2575
+    'ChromeDriverTest.testTakeElementScreenshotInIframe',
 ]
 
 _VERSION_SPECIFIC_FILTER = {}
@@ -1698,17 +1700,31 @@
 
   def testTakeElementScreenshot(self):
     self._driver.Load(self.GetHttpUrlForFile(
-                      '/chromedriver/page_with_redBox.html'))
+                      '/chromedriver/page_with_redbox.html'))
     elementScreenshot = self._driver.FindElement(
         'id', 'box').TakeElementScreenshot()
     self.assertIsNotNone(elementScreenshot)
     dataActualScreenshot = base64.b64decode(elementScreenshot)
     filenameOfGoldenScreenshot = os.path.join(chrome_paths.GetTestData(),
                                               'chromedriver/goldenScreenshots',
-                                              'redBoxScreenshot.png')
+                                              'redboxScreenshot.png')
     imageGoldenScreenshot = open(filenameOfGoldenScreenshot, 'rb').read()
     self.assertEquals(imageGoldenScreenshot, dataActualScreenshot)
 
+  def testTakeElementScreenshotInIframe(self):
+    self._driver.Load(self.GetHttpUrlForFile(
+                      '/chromedriver/page_with_iframe_redbox.html'))
+    frame = self._driver.FindElement('id', 'frm')
+    self._driver.SwitchToFrame(frame)
+    elementScreenshot = self._driver.FindElement(
+        'id', 'box').TakeElementScreenshot()
+    self.assertIsNotNone(elementScreenshot)
+    dataActualScreenshot = base64.b64decode(elementScreenshot)
+    filenameOfGoldenScreenshot = os.path.join(chrome_paths.GetTestData(),
+                                            'chromedriver/goldenScreenshots',
+                                            'redboxScreenshot.png')
+    imageGoldenScreenshot= open(filenameOfGoldenScreenshot, 'rb').read()
+    self.assertEquals(imageGoldenScreenshot, dataActualScreenshot)
 
 class ChromeDriverSiteIsolation(ChromeDriverBaseTestWithWebServer):
   """Tests for ChromeDriver with the new Site Isolation Chrome feature.
diff --git a/chrome/test/data/chromedriver/goldenScreenshots/redBoxScreenshot.png b/chrome/test/data/chromedriver/goldenScreenshots/redboxScreenshot.png
similarity index 100%
rename from chrome/test/data/chromedriver/goldenScreenshots/redBoxScreenshot.png
rename to chrome/test/data/chromedriver/goldenScreenshots/redboxScreenshot.png
Binary files differ
diff --git a/chrome/test/data/chromedriver/page_with_iframe_redbox.html b/chrome/test/data/chromedriver/page_with_iframe_redbox.html
new file mode 100644
index 0000000..c1459cc
--- /dev/null
+++ b/chrome/test/data/chromedriver/page_with_iframe_redbox.html
@@ -0,0 +1,7 @@
+<!DOCTYPE html>
+<html>
+  <body>
+    <iframe id="frm" width="300" height="200" src="page_with_redbox.html">
+    </iframe>
+  </body>
+</html>
\ No newline at end of file
diff --git a/chrome/test/data/chromedriver/page_with_redBox.html b/chrome/test/data/chromedriver/page_with_redbox.html
similarity index 100%
rename from chrome/test/data/chromedriver/page_with_redBox.html
rename to chrome/test/data/chromedriver/page_with_redbox.html
diff --git a/chrome/test/data/webui/cr_elements/cr_input_test.js b/chrome/test/data/webui/cr_elements/cr_input_test.js
index b482b7c..56cea48 100644
--- a/chrome/test/data/webui/cr_elements/cr_input_test.js
+++ b/chrome/test/data/webui/cr_elements/cr_input_test.js
@@ -181,8 +181,22 @@
         })
         .then(() => {
           input.blur();
+          whenTransitionEnd =
+              test_util.eventToPromise('transitionend', underline);
+          // Wait for underline to fade out.
+          return whenTransitionEnd;
+        })
+        .then(() => {
+          whenTransitionEnd =
+              test_util.eventToPromise('transitionend', underline);
           assertFalse(crInput.hasAttribute('focused_'));
           assertEquals('0', getComputedStyle(underline).opacity);
+          // The width transition has a delay larger than the opacity transition
+          // duration so that the width can be reset to 0 after the underline is
+          // no longer visible.
+          return whenTransitionEnd;
+        })
+        .then(() => {
           assertEquals(0, underline.offsetWidth);
         });
   });
diff --git a/chromecast/base/cast_features.cc b/chromecast/base/cast_features.cc
index 32465af..363be685 100644
--- a/chromecast/base/cast_features.cc
+++ b/chromecast/base/cast_features.cc
@@ -13,6 +13,7 @@
 #include "base/metrics/field_trial_param_associator.h"
 #include "base/metrics/field_trial_params.h"
 #include "base/no_destructor.h"
+#include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/values.h"
 
@@ -264,9 +265,7 @@
 }
 
 bool IsFeatureEnabled(const base::Feature& feature) {
-  DCHECK(std::find(GetFeatures().begin(), GetFeatures().end(), &feature) !=
-         GetFeatures().end())
-      << feature.name;
+  DCHECK(base::ContainsValue(GetFeatures(), &feature)) << feature.name;
   return base::FeatureList::IsEnabled(feature);
 }
 
diff --git a/chromecast/browser/cast_browser_main_parts.cc b/chromecast/browser/cast_browser_main_parts.cc
index 98ba530..3ee6d38 100644
--- a/chromecast/browser/cast_browser_main_parts.cc
+++ b/chromecast/browser/cast_browser_main_parts.cc
@@ -77,6 +77,7 @@
 #endif
 
 #if defined(OS_ANDROID)
+#include "base/task/post_task.h"
 #include "chromecast/app/android/crash_handler.h"
 #include "components/crash/content/browser/child_exit_observer_android.h"
 #include "components/crash/content/browser/child_process_crash_observer_android.h"
@@ -488,7 +489,13 @@
 #endif  // !defined(OS_ANDROID) && !defined(OS_FUCHSIA)
 
 #if defined(OS_ANDROID)
-  StartPeriodicCrashReportUpload();
+  crash_reporter_runner_ = base::CreateSequencedTaskRunnerWithTraits(
+      {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
+       base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN});
+  crash_reporter_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&CastBrowserMainParts::StartPeriodicCrashReportUpload,
+                     base::Unretained(this)));
 #endif  // defined(OS_ANDROID)
 
   cast_browser_process_->SetNetLog(net_log_.get());
diff --git a/chromecast/browser/cast_browser_main_parts.h b/chromecast/browser/cast_browser_main_parts.h
index c6036497..e48a944 100644
--- a/chromecast/browser/cast_browser_main_parts.h
+++ b/chromecast/browser/cast_browser_main_parts.h
@@ -108,6 +108,7 @@
 #if defined(OS_ANDROID)
   void StartPeriodicCrashReportUpload();
   void OnStartPeriodicCrashReportUpload();
+  scoped_refptr<base::SequencedTaskRunner> crash_reporter_runner_;
   std::unique_ptr<base::RepeatingTimer> crash_reporter_timer_;
 #endif
 
diff --git a/chromeos/test/data/oobe_configuration/TestDeviceRequisition.json b/chromeos/test/data/oobe_configuration/TestDeviceRequisition.json
new file mode 100644
index 0000000..e86edd7
--- /dev/null
+++ b/chromeos/test/data/oobe_configuration/TestDeviceRequisition.json
@@ -0,0 +1,5 @@
+{
+  "welcomeNext": true,
+  "networkSelectGuid": "eth1_guid",
+  "deviceRequisition": "some_requisition",
+}
diff --git a/components/autofill/core/browser/autofill_external_delegate_unittest.cc b/components/autofill/core/browser/autofill_external_delegate_unittest.cc
index 69706bcf..ef73d50d 100644
--- a/components/autofill/core/browser/autofill_external_delegate_unittest.cc
+++ b/components/autofill/core/browser/autofill_external_delegate_unittest.cc
@@ -181,11 +181,7 @@
 
   // The enums must be cast to ints to prevent compile errors on linux_rel.
   auto element_ids = testing::ElementsAre(
-      kAutofillProfileId,
-#if !defined(OS_ANDROID)
-      static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
-#endif
-      static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
+      kAutofillProfileId, static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
   EXPECT_CALL(
       autofill_client_,
       ShowAutofillPopup(_, _, SuggestionVectorIdsAre(element_ids), false, _));
@@ -221,9 +217,6 @@
   // The enums must be cast to ints to prevent compile errors on linux_rel.
   auto element_ids =
       testing::ElementsAre(kAutofillProfileId,
-#if !defined(OS_ANDROID)
-                           static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
-#endif
                            static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
 
   EXPECT_CALL(
@@ -308,11 +301,7 @@
 #if !defined(OS_ANDROID)
       static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
 #endif
-      kAutofillProfileId,
-#if !defined(OS_ANDROID)
-      static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
-#endif
-      static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
+      kAutofillProfileId, static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
   EXPECT_CALL(
       autofill_client_,
       ShowAutofillPopup(_, _, SuggestionVectorIdsAre(element_ids), false, _));
@@ -363,11 +352,7 @@
 #if !defined(OS_ANDROID)
       static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
 #endif
-      kAutofillProfileId,
-#if !defined(OS_ANDROID)
-      static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
-#endif
-      static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
+      kAutofillProfileId, static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
   EXPECT_CALL(
       autofill_client_,
       ShowAutofillPopup(_, _, SuggestionVectorIdsAre(element_ids), false, _));
@@ -411,17 +396,13 @@
                                                data_list_items);
 
   // The enums must be cast to ints to prevent compile errors on linux_rel.
-  auto element_ids =
-      testing::ElementsAre(static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY),
-                           static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY),
+  auto element_ids = testing::ElementsAre(
+      static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY),
+      static_cast<int>(POPUP_ITEM_ID_DATALIST_ENTRY),
 #if !defined(OS_ANDROID)
-                           static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
+      static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
 #endif
-                           kAutofillProfileId,
-#if !defined(OS_ANDROID)
-                           static_cast<int>(POPUP_ITEM_ID_SEPARATOR),
-#endif
-                           static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
+      kAutofillProfileId, static_cast<int>(POPUP_ITEM_ID_AUTOFILL_OPTIONS));
   EXPECT_CALL(
       autofill_client_,
       ShowAutofillPopup(_, _, SuggestionVectorIdsAre(element_ids), false, _));
@@ -747,9 +728,6 @@
   IssueOnQuery(kQueryId);
 
   auto element_icons = testing::ElementsAre(
-#if !defined(OS_ANDROID)
-      base::string16(),
-#endif
       base::string16(), base::ASCIIToUTF16("googlePay"));
   EXPECT_CALL(autofill_client_,
               ShowAutofillPopup(_, _, SuggestionVectorIconsAre(element_icons),
@@ -774,7 +752,7 @@
 
   auto element_icons =
       testing::ElementsAre(base::ASCIIToUTF16("googlePay"), base::string16(),
-                           base::string16(), base::ASCIIToUTF16("googlePay"));
+                           base::ASCIIToUTF16("googlePay"));
   EXPECT_CALL(autofill_client_,
               ShowAutofillPopup(_, _, SuggestionVectorIconsAre(element_icons),
                                 false, _));
@@ -797,7 +775,7 @@
   IssueOnQuery(kQueryId);
 
   auto element_icons = testing::ElementsAre(
-      base::string16(), base::string16(),
+      base::string16(),
       base::string16() /* Autofill setting item does not have icon. */);
   EXPECT_CALL(autofill_client_,
               ShowAutofillPopup(_, _, SuggestionVectorIconsAre(element_icons),
@@ -818,9 +796,6 @@
   IssueOnQuery(kQueryId);
 
   auto element_icons = testing::ElementsAre(
-#if !defined(OS_ANDROID)
-      base::string16(),
-#endif
       base::string16(),
       base::string16() /* Autofill setting item does not have icon. */);
   EXPECT_CALL(autofill_client_,
@@ -840,9 +815,6 @@
   IssueOnQuery(kQueryId);
 
   auto element_values = testing::ElementsAre(
-#if !defined(OS_ANDROID)
-      base::string16(),
-#endif
       base::string16(), l10n_util::GetStringUTF16(IDS_AUTOFILL_MANAGE));
   EXPECT_CALL(autofill_client_,
               ShowAutofillPopup(_, _, SuggestionVectorValuesAre(element_values),
diff --git a/components/autofill/core/browser/payments/full_card_request_unittest.cc b/components/autofill/core/browser/payments/full_card_request_unittest.cc
index 6b6dbda..a846f471 100644
--- a/components/autofill/core/browser/payments/full_card_request_unittest.cc
+++ b/components/autofill/core/browser/payments/full_card_request_unittest.cc
@@ -59,11 +59,8 @@
 // The personal data manager.
 class MockPersonalDataManager : public PersonalDataManager {
  public:
-  MockPersonalDataManager() : PersonalDataManager("en-US") {
-    testing::DefaultValue<bool>::Set(true);
-  }
+  MockPersonalDataManager() : PersonalDataManager("en-US") {}
   ~MockPersonalDataManager() override {}
-  MOCK_CONST_METHOD0(IsSyncFeatureEnabled, bool());
   MOCK_METHOD1(UpdateCreditCard, void(const CreditCard& credit_card));
   MOCK_METHOD1(UpdateServerCreditCard, void(const CreditCard& credit_card));
 };
diff --git a/components/autofill/core/browser/payments/payments_client.cc b/components/autofill/core/browser/payments/payments_client.cc
index 27e1855..d626c67 100644
--- a/components/autofill/core/browser/payments/payments_client.cc
+++ b/components/autofill/core/browser/payments/payments_client.cc
@@ -237,12 +237,9 @@
 class UnmaskCardRequest : public PaymentsRequest {
  public:
   UnmaskCardRequest(const PaymentsClient::UnmaskRequestDetails& request_details,
-                    const bool full_sync_enabled,
                     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                                             const std::string&)> callback)
-      : request_details_(request_details),
-        full_sync_enabled_(full_sync_enabled),
-        callback_(std::move(callback)) {
+      : request_details_(request_details), callback_(std::move(callback)) {
     DCHECK(
         CreditCard::MASKED_SERVER_CARD == request_details.card.record_type() ||
         CreditCard::FULL_SERVER_CARD == request_details.card.record_type());
@@ -270,13 +267,6 @@
     }
     request_dict.Set("context", std::move(context));
 
-    if (ShouldUseActiveSignedInAccount()) {
-      std::unique_ptr<base::DictionaryValue> chrome_user_context(
-          new base::DictionaryValue());
-      chrome_user_context->SetBoolean("full_sync_enabled", full_sync_enabled_);
-      request_dict.Set("chrome_user_context", std::move(chrome_user_context));
-    }
-
     int value = 0;
     if (base::StringToInt(request_details_.user_response.exp_month, &value))
       request_dict.SetInteger("expiration_month", value);
@@ -307,7 +297,6 @@
 
  private:
   PaymentsClient::UnmaskRequestDetails request_details_;
-  const bool full_sync_enabled_;
   base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                           const std::string&)>
       callback_;
@@ -320,7 +309,6 @@
       const std::vector<AutofillProfile>& addresses,
       const int detected_values,
       const std::vector<const char*>& active_experiments,
-      const bool full_sync_enabled,
       const std::string& app_locale,
       base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                               const base::string16&,
@@ -329,7 +317,6 @@
       : addresses_(addresses),
         detected_values_(detected_values),
         active_experiments_(active_experiments),
-        full_sync_enabled_(full_sync_enabled),
         app_locale_(app_locale),
         callback_(std::move(callback)),
         billable_service_number_(billable_service_number) {}
@@ -348,13 +335,6 @@
     context->SetInteger("billable_service", billable_service_number_);
     request_dict.Set("context", std::move(context));
 
-    if (ShouldUseActiveSignedInAccount()) {
-      std::unique_ptr<base::DictionaryValue> chrome_user_context(
-          new base::DictionaryValue());
-      chrome_user_context->SetBoolean("full_sync_enabled", full_sync_enabled_);
-      request_dict.Set("chrome_user_context", std::move(chrome_user_context));
-    }
-
     std::unique_ptr<base::ListValue> addresses(new base::ListValue());
     for (const AutofillProfile& profile : addresses_) {
       // These addresses are used by Payments to (1) accurately determine the
@@ -400,7 +380,6 @@
   const std::vector<AutofillProfile> addresses_;
   const int detected_values_;
   const std::vector<const char*> active_experiments_;
-  const bool full_sync_enabled_;
   std::string app_locale_;
   base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                           const base::string16&,
@@ -414,12 +393,9 @@
 class UploadCardRequest : public PaymentsRequest {
  public:
   UploadCardRequest(const PaymentsClient::UploadRequestDetails& request_details,
-                    const bool full_sync_enabled,
                     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                                             const std::string&)> callback)
-      : request_details_(request_details),
-        full_sync_enabled_(full_sync_enabled),
-        callback_(std::move(callback)) {}
+      : request_details_(request_details), callback_(std::move(callback)) {}
   ~UploadCardRequest() override {}
 
   std::string GetRequestUrlPath() override { return kUploadCardRequestPath; }
@@ -447,13 +423,6 @@
     }
     request_dict.Set("context", std::move(context));
 
-    if (ShouldUseActiveSignedInAccount()) {
-      std::unique_ptr<base::DictionaryValue> chrome_user_context(
-          new base::DictionaryValue());
-      chrome_user_context->SetBoolean("full_sync_enabled", full_sync_enabled_);
-      request_dict.Set("chrome_user_context", std::move(chrome_user_context));
-    }
-
     SetStringIfNotEmpty(request_details_.card, CREDIT_CARD_NAME_FULL,
                         app_locale, "cardholder_name", &request_dict);
 
@@ -512,7 +481,6 @@
 
  private:
   const PaymentsClient::UploadRequestDetails request_details_;
-  const bool full_sync_enabled_;
   base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                           const std::string&)>
       callback_;
@@ -524,11 +492,9 @@
   MigrateCardsRequest(
       const PaymentsClient::MigrationRequestDetails& request_details,
       const std::vector<MigratableCreditCard>& migratable_credit_cards,
-      const bool full_sync_enabled,
       MigrateCardsCallback callback)
       : request_details_(request_details),
         migratable_credit_cards_(migratable_credit_cards),
-        full_sync_enabled_(full_sync_enabled),
         callback_(std::move(callback)) {}
   ~MigrateCardsRequest() override {}
 
@@ -556,13 +522,6 @@
     }
     request_dict.Set("context", std::move(context));
 
-    if (ShouldUseActiveSignedInAccount()) {
-      std::unique_ptr<base::DictionaryValue> chrome_user_context(
-          new base::DictionaryValue());
-      chrome_user_context->SetBoolean("full_sync_enabled", full_sync_enabled_);
-      request_dict.Set("chrome_user_context", std::move(chrome_user_context));
-    }
-
     request_dict.SetString("context_token", request_details_.context_token);
 
     std::string all_pans_data = std::string();
@@ -638,7 +597,6 @@
 
   const PaymentsClient::MigrationRequestDetails request_details_;
   const std::vector<MigratableCreditCard>& migratable_credit_cards_;
-  const bool full_sync_enabled_;
   MigrateCardsCallback callback_;
   std::unique_ptr<std::unordered_map<std::string, std::string>> save_result_;
   std::string display_text_;
@@ -694,9 +652,7 @@
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                             const std::string&)> callback) {
   IssueRequest(
-      std::make_unique<UnmaskCardRequest>(
-          request_details, account_info_getter_->IsSyncFeatureEnabled(),
-          std::move(callback)),
+      std::make_unique<UnmaskCardRequest>(request_details, std::move(callback)),
       true);
 }
 
@@ -710,8 +666,7 @@
                             std::unique_ptr<base::DictionaryValue>)> callback,
     const int billable_service_number) {
   IssueRequest(std::make_unique<GetUploadDetailsRequest>(
-                   addresses, detected_values, active_experiments,
-                   account_info_getter_->IsSyncFeatureEnabled(), app_locale,
+                   addresses, detected_values, active_experiments, app_locale,
                    std::move(callback), billable_service_number),
                false);
 }
@@ -721,9 +676,7 @@
     base::OnceCallback<void(AutofillClient::PaymentsRpcResult,
                             const std::string&)> callback) {
   IssueRequest(
-      std::make_unique<UploadCardRequest>(
-          request_details, account_info_getter_->IsSyncFeatureEnabled(),
-          std::move(callback)),
+      std::make_unique<UploadCardRequest>(request_details, std::move(callback)),
       true);
 }
 
@@ -733,8 +686,7 @@
     MigrateCardsCallback callback) {
   IssueRequest(
       std::make_unique<MigrateCardsRequest>(
-          request_details, migratable_credit_cards,
-          account_info_getter_->IsSyncFeatureEnabled(), std::move(callback)),
+          request_details, migratable_credit_cards, std::move(callback)),
       /*authenticate=*/true);
 }
 
diff --git a/components/autofill/core/browser/payments/payments_client_unittest.cc b/components/autofill/core/browser/payments/payments_client_unittest.cc
index ec135c8e..4550d30 100644
--- a/components/autofill/core/browser/payments/payments_client_unittest.cc
+++ b/components/autofill/core/browser/payments/payments_client_unittest.cc
@@ -321,51 +321,6 @@
   EXPECT_EQ("1234", real_pan_);
 }
 
-TEST_F(PaymentsClientTest, UnmaskIncludesChromeUserContext) {
-  scoped_feature_list_.InitWithFeatures(
-      {features::kAutofillGetPaymentsIdentityFromSync},  // Enabled
-      {features::kAutofillEnableAccountWalletStorage});  // Disabled
-
-  StartUnmasking();
-  IssueOAuthToken();
-  ReturnResponse(net::HTTP_OK, "{}");
-
-  // ChromeUserContext was set.
-  EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos);
-  EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
-}
-
-TEST_F(PaymentsClientTest,
-       UnmaskIncludesChromeUserContextIfWalletStorageFlagEnabled) {
-  scoped_feature_list_.InitWithFeatures(
-      {features::kAutofillEnableAccountWalletStorage},    // Enabled
-      {features::kAutofillGetPaymentsIdentityFromSync});  // Disabled
-
-  StartUnmasking();
-  IssueOAuthToken();
-  ReturnResponse(net::HTTP_OK, "{}");
-
-  // ChromeUserContext was set.
-  EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos);
-  EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
-}
-
-TEST_F(PaymentsClientTest, UnmaskExcludesChromeUserContextIfExperimentsOff) {
-  scoped_feature_list_.InitWithFeatures(
-      {},  // Enabled
-      {features::kAutofillEnableAccountWalletStorage,
-       features::kAutofillGetPaymentsIdentityFromSync});  // Disabled
-
-  StartUnmasking();
-  IssueOAuthToken();
-  ReturnResponse(net::HTTP_OK, "{}");
-
-  // ChromeUserContext was not set.
-  EXPECT_TRUE(!GetUploadData().empty());
-  EXPECT_TRUE(GetUploadData().find("chrome_user_context") == std::string::npos);
-  EXPECT_TRUE(GetUploadData().find("full_sync_enabled") == std::string::npos);
-}
-
 TEST_F(PaymentsClientTest, GetDetailsSuccess) {
   StartGettingUploadDetails();
   ReturnResponse(
@@ -408,46 +363,6 @@
               std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, GetDetailsIncludesChromeUserContext) {
-  scoped_feature_list_.InitWithFeatures(
-      {features::kAutofillGetPaymentsIdentityFromSync},  // Enabled
-      {features::kAutofillEnableAccountWalletStorage});  // Disabled
-
-  StartGettingUploadDetails();
-
-  // ChromeUserContext was set.
-  EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos);
-  EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
-}
-
-TEST_F(PaymentsClientTest,
-       GetDetailsIncludesChromeUserContextIfWalletStorageFlagEnabled) {
-  scoped_feature_list_.InitWithFeatures(
-      {features::kAutofillEnableAccountWalletStorage},    // Enabled
-      {features::kAutofillGetPaymentsIdentityFromSync});  // Disabled
-
-  StartGettingUploadDetails();
-
-  // ChromeUserContext was set.
-  EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos);
-  EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
-}
-
-TEST_F(PaymentsClientTest,
-       GetDetailsExcludesChromeUserContextIfExperimentsOff) {
-  scoped_feature_list_.InitWithFeatures(
-      {},  // Enabled
-      {features::kAutofillEnableAccountWalletStorage,
-       features::kAutofillGetPaymentsIdentityFromSync});  // Disabled
-
-  StartGettingUploadDetails();
-
-  // ChromeUserContext was not set.
-  EXPECT_TRUE(!GetUploadData().empty());
-  EXPECT_TRUE(GetUploadData().find("chrome_user_context") == std::string::npos);
-  EXPECT_TRUE(GetUploadData().find("full_sync_enabled") == std::string::npos);
-}
-
 TEST_F(PaymentsClientTest, GetUploadAccountFromSyncTest) {
   EnableAutofillGetPaymentsIdentityFromSync();
   // Set up a different account.
@@ -685,48 +600,6 @@
   EXPECT_TRUE(GetUploadData().find("&s7e_13_cvc=") != std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, UploadIncludesChromeUserContext) {
-  scoped_feature_list_.InitWithFeatures(
-      {features::kAutofillGetPaymentsIdentityFromSync},  // Enabled
-      {features::kAutofillEnableAccountWalletStorage});  // Disabled
-
-  StartUploading(/*include_cvc=*/true);
-  IssueOAuthToken();
-
-  // ChromeUserContext was set.
-  EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos);
-  EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
-}
-
-TEST_F(PaymentsClientTest,
-       UploadIncludesChromeUserContextIfWalletStorageFlagEnabled) {
-  scoped_feature_list_.InitWithFeatures(
-      {features::kAutofillEnableAccountWalletStorage},    // Enabled
-      {features::kAutofillGetPaymentsIdentityFromSync});  // Disabled
-
-  StartUploading(/*include_cvc=*/true);
-  IssueOAuthToken();
-
-  // ChromeUserContext was set.
-  EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos);
-  EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
-}
-
-TEST_F(PaymentsClientTest, UploadExcludesChromeUserContextIfExperimentsOff) {
-  scoped_feature_list_.InitWithFeatures(
-      {},  // Enabled
-      {features::kAutofillEnableAccountWalletStorage,
-       features::kAutofillGetPaymentsIdentityFromSync});  // Disabled
-
-  StartUploading(/*include_cvc=*/true);
-  IssueOAuthToken();
-
-  // ChromeUserContext was not set.
-  EXPECT_TRUE(!GetUploadData().empty());
-  EXPECT_TRUE(GetUploadData().find("chrome_user_context") == std::string::npos);
-  EXPECT_TRUE(GetUploadData().find("full_sync_enabled") == std::string::npos);
-}
-
 TEST_F(PaymentsClientTest, UploadDoesNotIncludeCvcInRequestIfNotProvided) {
   StartUploading(/*include_cvc=*/false);
   IssueOAuthToken();
@@ -802,49 +675,6 @@
   EXPECT_TRUE(GetUploadData().find("cardholder_name") == std::string::npos);
 }
 
-TEST_F(PaymentsClientTest, MigrationRequestIncludesChromeUserContext) {
-  scoped_feature_list_.InitWithFeatures(
-      {features::kAutofillGetPaymentsIdentityFromSync},  // Enabled
-      {features::kAutofillEnableAccountWalletStorage});  // Disabled
-
-  StartMigrating(/*uncheck_last_card=*/false, /*has_cardholder_name=*/true);
-  IssueOAuthToken();
-
-  // ChromeUserContext was set.
-  EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos);
-  EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
-}
-
-TEST_F(PaymentsClientTest,
-       MigrationRequestIncludesChromeUserContextIfWalletStorageFlagEnabled) {
-  scoped_feature_list_.InitWithFeatures(
-      {features::kAutofillEnableAccountWalletStorage},    // Enabled
-      {features::kAutofillGetPaymentsIdentityFromSync});  // Disabled
-
-  StartMigrating(/*uncheck_last_card=*/false, /*has_cardholder_name=*/true);
-  IssueOAuthToken();
-
-  // ChromeUserContext was set.
-  EXPECT_TRUE(GetUploadData().find("chrome_user_context") != std::string::npos);
-  EXPECT_TRUE(GetUploadData().find("full_sync_enabled") != std::string::npos);
-}
-
-TEST_F(PaymentsClientTest,
-       MigrationRequestExcludesChromeUserContextIfExperimentsOff) {
-  scoped_feature_list_.InitWithFeatures(
-      {},  // Enabled
-      {features::kAutofillEnableAccountWalletStorage,
-       features::kAutofillGetPaymentsIdentityFromSync});  // Disabled
-
-  StartMigrating(/*uncheck_last_card=*/false, /*has_cardholder_name=*/true);
-  IssueOAuthToken();
-
-  // ChromeUserContext was not set.
-  EXPECT_TRUE(!GetUploadData().empty());
-  EXPECT_TRUE(GetUploadData().find("chrome_user_context") == std::string::npos);
-  EXPECT_TRUE(GetUploadData().find("full_sync_enabled") == std::string::npos);
-}
-
 TEST_F(PaymentsClientTest, MigrationSuccessWithSaveResult) {
   StartMigrating(/*uncheck_last_card=*/false, /*has_cardholder_name=*/true);
   IssueOAuthToken();
diff --git a/components/autofill/core/browser/personal_data_manager.cc b/components/autofill/core/browser/personal_data_manager.cc
index d876068..2707895 100644
--- a/components/autofill/core/browser/personal_data_manager.cc
+++ b/components/autofill/core/browser/personal_data_manager.cc
@@ -433,9 +433,11 @@
       return;
     }
 
-    if (server_database_ != nullptr && server_database_ != profile_database_) {
-      // Remove the previous observer if we had any.
-      server_database_->RemoveObserver(personal_data_manager_);
+    if (server_database_ != nullptr) {
+      if (server_database_ != profile_database_) {
+        // Remove the previous observer if we had any.
+        server_database_->RemoveObserver(personal_data_manager_);
+      }
       personal_data_manager_->CancelPendingServerQueries();
     }
     server_database_ = new_server_database;
@@ -558,6 +560,13 @@
       ResetFullServerCards(/*dry_run=*/!base::FeatureList::IsEnabled(
           features::kAutofillResetFullServerCardsOnAuthError));
     }
+    if (base::FeatureList::IsEnabled(
+            autofill::features::kAutofillEnableAccountWalletStorage)) {
+      // Use the ephemeral account storage when the user didn't enable the sync
+      // feature explicitly.
+      database_helper_->SetUseAccountStorageForServerCards(
+          !sync_service->IsSyncFeatureEnabled());
+    }
   }
 }
 
@@ -1859,6 +1868,9 @@
   if (pending_server_creditcards_query_) {
     CancelPendingServerQuery(&pending_server_creditcards_query_);
   }
+  if (pending_customer_data_query_) {
+    CancelPendingServerQuery(&pending_customer_data_query_);
+  }
   // TODO(crbug.com/864519): also cancel the server addresses query once they
   // use the account storage.
 }
diff --git a/components/autofill/core/browser/personal_data_manager_unittest.cc b/components/autofill/core/browser/personal_data_manager_unittest.cc
index 44b9ba1..357e6e5 100644
--- a/components/autofill/core/browser/personal_data_manager_unittest.cc
+++ b/components/autofill/core/browser/personal_data_manager_unittest.cc
@@ -179,8 +179,8 @@
             : nullptr,
         prefs_.get(), identity_test_env_.identity_manager(), is_incognito);
     personal_data_->AddObserver(&personal_data_observer_);
-    personal_data_->OnSyncServiceInitialized(&sync_service_);
     sync_service_.SetIsAuthenticatedAccountPrimary(!use_account_server_storage);
+    personal_data_->OnSyncServiceInitialized(&sync_service_);
     personal_data_->OnStateChanged(&sync_service_);
 
     // Verify that the web database has been updated and the notification sent.
@@ -6206,6 +6206,8 @@
 
   // Call OnSyncServiceInitialized with a sync service in auth error.
   TestSyncService sync_service;
+  sync_service.SetIsAuthenticatedAccountPrimary(
+      /*is_authenticated_account_primary=*/false);
   sync_service.SetInAuthError(true);
   personal_data_->OnSyncServiceInitialized(&sync_service);
   WaitForOnPersonalDataChanged();
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
index 05f52738..9bc109a 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
+++ b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.cc
@@ -187,6 +187,17 @@
   return false;
 }
 
+AutofillWalletSyncBridge::StopSyncResponse
+AutofillWalletSyncBridge::ApplyStopSyncChanges(
+    std::unique_ptr<syncer::MetadataChangeList> delete_metadata_change_list) {
+  // If a metadata change list gets passed in, that means sync is actually
+  // disabled, so we want to delete the payments data.
+  if (delete_metadata_change_list) {
+    SetSyncData(syncer::EntityChangeList());
+  }
+  return StopSyncResponse::kModelStillReadyToSync;
+}
+
 void AutofillWalletSyncBridge::SetSyncData(
     const syncer::EntityChangeList& entity_data) {
   bool wallet_data_changed = false;
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h
index 24baedc..2217cda0 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h
+++ b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge.h
@@ -63,6 +63,9 @@
   std::string GetClientTag(const syncer::EntityData& entity_data) override;
   std::string GetStorageKey(const syncer::EntityData& entity_data) override;
   bool SupportsIncrementalUpdates() const override;
+  StopSyncResponse ApplyStopSyncChanges(
+      std::unique_ptr<syncer::MetadataChangeList> delete_metadata_change_list)
+      override;
 
  private:
   struct AutofillWalletDiff {
diff --git a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc
index 0be25a1..5fdc7834 100644
--- a/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc
+++ b/components/autofill/core/browser/webdata/autofill_wallet_sync_bridge_unittest.cc
@@ -32,6 +32,7 @@
 #include "components/sync/model/mock_model_type_change_processor.h"
 #include "components/sync/model/sync_data.h"
 #include "components/sync/model_impl/client_tag_based_model_type_processor.h"
+#include "components/sync/model_impl/in_memory_metadata_change_list.h"
 #include "components/sync/protocol/autofill_specifics.pb.h"
 #include "components/sync/protocol/sync.pb.h"
 #include "components/sync/test/test_matchers.h"
@@ -606,6 +607,36 @@
   ResetBridge();
 }
 
+TEST_F(AutofillWalletSyncBridgeTest, ApplyStopSyncChanges_ClearAllData) {
+  // Create one profile and one card on the client.
+  AutofillProfile local_profile = test::GetServerProfile();
+  table()->SetServerProfiles({local_profile});
+  CreditCard local_card = test::GetMaskedServerCard();
+  table()->SetServerCreditCards({local_card});
+
+  EXPECT_CALL(*backend(), NotifyOfMultipleAutofillChanges());
+  // Passing in a non-null metadata change list indicates to the bridge that
+  // sync is stopping because it was disabled.
+  bridge()->ApplyStopSyncChanges(
+      std::make_unique<syncer::InMemoryMetadataChangeList>());
+
+  EXPECT_TRUE(GetAllLocalData().empty());
+}
+
+TEST_F(AutofillWalletSyncBridgeTest, ApplyStopSyncChanges_KeepData) {
+  // Create one profile and one card on the client.
+  AutofillProfile local_profile = test::GetServerProfile();
+  table()->SetServerProfiles({local_profile});
+  CreditCard local_card = test::GetMaskedServerCard();
+  table()->SetServerCreditCards({local_card});
+
+  // Passing in a non-null metadata change list indicates to the bridge that
+  // sync is stopping but the data type is not disabled.
+  bridge()->ApplyStopSyncChanges(/*delete_metadata_change_list=*/nullptr);
+
+  EXPECT_FALSE(GetAllLocalData().empty());
+}
+
 class AutofillWalletEphemeralSyncBridgeTest
     : public AutofillWalletSyncBridgeTest {
  public:
diff --git a/components/autofill/core/common/autofill_features.cc b/components/autofill/core/common/autofill_features.cc
index 512bded..9c88857 100644
--- a/components/autofill/core/common/autofill_features.cc
+++ b/components/autofill/core/common/autofill_features.cc
@@ -100,7 +100,7 @@
     base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kAutofillExpandedPopupViews{
-    "AutofillExpandedPopupViews", base::FEATURE_DISABLED_BY_DEFAULT};
+    "AutofillExpandedPopupViews", base::FEATURE_ENABLED_BY_DEFAULT};
 
 // When enabled, gets payment identity from sync service instead of
 // identity manager.
@@ -170,7 +170,7 @@
 // are sent.
 const base::Feature kAutofillSendOnlyCountryInGetUploadDetails{
     "AutofillSendOnlyCountryInGetUploadDetails",
-    base::FEATURE_DISABLED_BY_DEFAULT};
+    base::FEATURE_ENABLED_BY_DEFAULT};
 
 // Enables or Disables (mostly for hermetic testing) autofill server
 // communication. The URL of the autofill server can further be controlled via
@@ -254,7 +254,7 @@
 // Controls whether the PaymentsCustomerData is used to make requests to
 // Google Payments.
 const base::Feature kAutofillUsePaymentsCustomerData{
-    "AutofillUsePaymentsCustomerData", base::FEATURE_DISABLED_BY_DEFAULT};
+    "AutofillUsePaymentsCustomerData", base::FEATURE_ENABLED_BY_DEFAULT};
 
 const base::Feature kAutofillVoteUsingInvalidProfileData{
     "AutofillVoteUsingInvalidProfileData", base::FEATURE_ENABLED_BY_DEFAULT};
diff --git a/components/autofill/ios/browser/autofill_agent.mm b/components/autofill/ios/browser/autofill_agent.mm
index 80e7db5..e268e13 100644
--- a/components/autofill/ios/browser/autofill_agent.mm
+++ b/components/autofill/ios/browser/autofill_agent.mm
@@ -36,11 +36,11 @@
 #import "components/autofill/ios/browser/form_suggestion.h"
 #import "components/autofill/ios/browser/js_autofill_manager.h"
 #import "components/autofill/ios/form_util/form_activity_observer_bridge.h"
+#include "components/autofill/ios/form_util/form_activity_params.h"
 #import "components/prefs/ios/pref_observer_bridge.h"
 #include "components/prefs/pref_change_registrar.h"
 #include "components/prefs/pref_service.h"
 #include "ios/web/public/url_scheme_util.h"
-#include "ios/web/public/web_state/form_activity_params.h"
 #import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
 #import "ios/web/public/web_state/navigation_context.h"
 #include "ios/web/public/web_state/url_verification_constants.h"
@@ -583,7 +583,7 @@
 #pragma mark FormActivityObserver
 
 - (void)webState:(web::WebState*)webState
-    didRegisterFormActivity:(const web::FormActivityParams&)params {
+    didRegisterFormActivity:(const autofill::FormActivityParams&)params {
   if (![self isAutofillEnabled])
     return;
 
diff --git a/components/autofill/ios/form_util/BUILD.gn b/components/autofill/ios/form_util/BUILD.gn
index 30daeef2..e0a7309d 100644
--- a/components/autofill/ios/form_util/BUILD.gn
+++ b/components/autofill/ios/form_util/BUILD.gn
@@ -11,6 +11,8 @@
     "form_activity_observer.h",
     "form_activity_observer_bridge.h",
     "form_activity_observer_bridge.mm",
+    "form_activity_params.cc",
+    "form_activity_params.h",
     "form_activity_tab_helper.h",
     "form_activity_tab_helper.mm",
   ]
diff --git a/components/autofill/ios/form_util/form_activity_observer.h b/components/autofill/ios/form_util/form_activity_observer.h
index a0c70101..715f130a 100644
--- a/components/autofill/ios/form_util/form_activity_observer.h
+++ b/components/autofill/ios/form_util/form_activity_observer.h
@@ -11,11 +11,12 @@
 
 namespace web {
 class WebState;
-struct FormActivityParams;
 }  // namespace web
 
 namespace autofill {
 
+struct FormActivityParams;
+
 // Interface for observing form activity.
 // It is the responsibility of the observer to unregister if the web_state
 // becomes invalid.
@@ -27,8 +28,9 @@
   // Called when the user is typing on a form field in the main frame or in a
   // same-origin iframe. |params.input_missing| is indicating if there is any
   // error when parsing the form field information.
-  virtual void FormActivityRegistered(web::WebState* web_state,
-                                      const web::FormActivityParams& params) {}
+  virtual void FormActivityRegistered(
+      web::WebState* web_state,
+      const FormActivityParams& params) {}
 
   // Called on form submission in the main frame or in a same-origin iframe.
   // |has_user_gesture| is true if the user interacted with the page.
diff --git a/components/autofill/ios/form_util/form_activity_observer_bridge.h b/components/autofill/ios/form_util/form_activity_observer_bridge.h
index a2689cfd..4ddb5ba2 100644
--- a/components/autofill/ios/form_util/form_activity_observer_bridge.h
+++ b/components/autofill/ios/form_util/form_activity_observer_bridge.h
@@ -14,7 +14,7 @@
 @optional
 // Invoked by WebStateObserverBridge::FormActivity.
 - (void)webState:(web::WebState*)webState
-    didRegisterFormActivity:(const web::FormActivityParams&)params;
+    didRegisterFormActivity:(const autofill::FormActivityParams&)params;
 
 // Invoked by WebStateObserverBridge::DidSubmitDocument.
 - (void)webState:(web::WebState*)webState
@@ -41,8 +41,9 @@
   ~FormActivityObserverBridge() override;
 
   // FormActivityObserver overrides:
-  void FormActivityRegistered(web::WebState* web_state,
-                              const web::FormActivityParams& params) override;
+  void FormActivityRegistered(
+      web::WebState* web_state,
+      const FormActivityParams& params) override;
 
   void DocumentSubmitted(web::WebState* web_state,
                          const std::string& form_name,
diff --git a/components/autofill/ios/form_util/form_activity_observer_bridge.mm b/components/autofill/ios/form_util/form_activity_observer_bridge.mm
index 757ac11..05627f3 100644
--- a/components/autofill/ios/form_util/form_activity_observer_bridge.mm
+++ b/components/autofill/ios/form_util/form_activity_observer_bridge.mm
@@ -26,7 +26,7 @@
 
 void FormActivityObserverBridge::FormActivityRegistered(
     web::WebState* web_state,
-    const web::FormActivityParams& params) {
+    const FormActivityParams& params) {
   DCHECK_EQ(web_state, web_state_);
   if ([owner_
           respondsToSelector:@selector(webState:didRegisterFormActivity:)]) {
diff --git a/components/autofill/ios/form_util/form_activity_observer_bridge_unittest.mm b/components/autofill/ios/form_util/form_activity_observer_bridge_unittest.mm
index 6793865..679b418 100644
--- a/components/autofill/ios/form_util/form_activity_observer_bridge_unittest.mm
+++ b/components/autofill/ios/form_util/form_activity_observer_bridge_unittest.mm
@@ -50,7 +50,7 @@
 }
 
 - (void)webState:(web::WebState*)webState
-    didRegisterFormActivity:(const web::FormActivityParams&)params {
+    didRegisterFormActivity:(const autofill::FormActivityParams&)params {
   _formActivityInfo = std::make_unique<autofill::TestFormActivityInfo>();
   _formActivityInfo->web_state = webState;
   _formActivityInfo->form_activity = params;
@@ -91,7 +91,7 @@
 TEST_F(FormActivityObserverBridgeTest, FormActivityRegistered) {
   ASSERT_FALSE([observer_ formActivityInfo]);
 
-  web::FormActivityParams params;
+  autofill::FormActivityParams params;
   params.form_name = "form-name";
   params.field_name = "field-name";
   params.field_type = "field-type";
diff --git a/ios/web/web_state/form_activity_params.cc b/components/autofill/ios/form_util/form_activity_params.cc
similarity index 75%
rename from ios/web/web_state/form_activity_params.cc
rename to components/autofill/ios/form_util/form_activity_params.cc
index 07bc2e3..4d0dc9e 100644
--- a/ios/web/web_state/form_activity_params.cc
+++ b/components/autofill/ios/form_util/form_activity_params.cc
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "ios/web/public/web_state/form_activity_params.h"
+#include "components/autofill/ios/form_util/form_activity_params.h"
 
-namespace web {
+namespace autofill {
 
 FormActivityParams::FormActivityParams() = default;
 FormActivityParams::FormActivityParams(const FormActivityParams& other) =
     default;
 FormActivityParams::~FormActivityParams() = default;
 
-}  // namespace web
+}  // namespace autofill
diff --git a/ios/web/public/web_state/form_activity_params.h b/components/autofill/ios/form_util/form_activity_params.h
similarity index 85%
rename from ios/web/public/web_state/form_activity_params.h
rename to components/autofill/ios/form_util/form_activity_params.h
index 7127746..e7ab0ec 100644
--- a/ios/web/public/web_state/form_activity_params.h
+++ b/components/autofill/ios/form_util/form_activity_params.h
@@ -1,12 +1,12 @@
 // Copyright 2017 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-#ifndef IOS_WEB_PUBLIC_WEB_STATE_FORM_ACTIVITY_PARAMS_H_
-#define IOS_WEB_PUBLIC_WEB_STATE_FORM_ACTIVITY_PARAMS_H_
+#ifndef COMPONENTS_AUTOFILL_IOS_FORM_UTIL_FORM_ACTIVITY_PARAMS_H_
+#define COMPONENTS_AUTOFILL_IOS_FORM_UTIL_FORM_ACTIVITY_PARAMS_H_
 
 #include <string>
 
-namespace web {
+namespace autofill {
 
 // Wraps information about event happening in a form.
 // Example HTML
@@ -48,6 +48,6 @@
   bool has_user_gesture = false;
 };
 
-}  // namespace web
+}  // namespace autofill
 
-#endif  // IOS_WEB_PUBLIC_WEB_STATE_FORM_ACTIVITY_PARAMS_H_
+#endif  // COMPONENTS_AUTOFILL_IOS_FORM_UTIL_FORM_ACTIVITY_PARAMS_H_
diff --git a/components/autofill/ios/form_util/form_activity_tab_helper.mm b/components/autofill/ios/form_util/form_activity_tab_helper.mm
index 7311c45..2ca1923 100644
--- a/components/autofill/ios/form_util/form_activity_tab_helper.mm
+++ b/components/autofill/ios/form_util/form_activity_tab_helper.mm
@@ -8,7 +8,7 @@
 
 #include "base/values.h"
 #include "components/autofill/ios/form_util/form_activity_observer.h"
-#include "ios/web/public/web_state/form_activity_params.h"
+#include "components/autofill/ios/form_util/form_activity_params.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
 #error "This file requires ARC support."
@@ -83,7 +83,7 @@
     const base::DictionaryValue& message,
     bool has_user_gesture,
     bool form_in_main_frame) {
-  web::FormActivityParams params;
+  FormActivityParams params;
   if (!message.GetString("formName", &params.form_name) ||
       !message.GetString("fieldName", &params.field_name) ||
       !message.GetString("fieldIdentifier", &params.field_identifier) ||
diff --git a/components/autofill/ios/form_util/test_form_activity_observer.h b/components/autofill/ios/form_util/test_form_activity_observer.h
index 662c561..55f3d6d 100644
--- a/components/autofill/ios/form_util/test_form_activity_observer.h
+++ b/components/autofill/ios/form_util/test_form_activity_observer.h
@@ -6,7 +6,7 @@
 #define COMPONENTS_AUTOFILL_IOS_FORM_UTIL_TEST_FORM_ACTIVITY_OBSERVER_H_
 
 #include "components/autofill/ios/form_util/form_activity_observer.h"
-#include "ios/web/public/web_state/form_activity_params.h"
+#include "components/autofill/ios/form_util/form_activity_params.h"
 
 namespace web {
 class WebState;
@@ -24,7 +24,7 @@
 // Arguments passed to |FormActivityRegistered|.
 struct TestFormActivityInfo {
   web::WebState* web_state;
-  web::FormActivityParams form_activity;
+  FormActivityParams form_activity;
 };
 
 class TestFormActivityObserver : public autofill::FormActivityObserver {
@@ -44,7 +44,7 @@
                          bool form_in_main_frame) override;
 
   void FormActivityRegistered(web::WebState* web_state,
-                              const web::FormActivityParams& params) override;
+                              const FormActivityParams& params) override;
 
  private:
   web::WebState* web_state_ = nullptr;
diff --git a/components/autofill/ios/form_util/test_form_activity_observer.mm b/components/autofill/ios/form_util/test_form_activity_observer.mm
index 71fb2c61..47c1803 100644
--- a/components/autofill/ios/form_util/test_form_activity_observer.mm
+++ b/components/autofill/ios/form_util/test_form_activity_observer.mm
@@ -38,7 +38,7 @@
 
 void TestFormActivityObserver::FormActivityRegistered(
     web::WebState* web_state,
-    const web::FormActivityParams& params) {
+    const FormActivityParams& params) {
   ASSERT_EQ(web_state_, web_state);
   form_activity_info_ = std::make_unique<TestFormActivityInfo>();
   form_activity_info_->web_state = web_state;
diff --git a/components/autofill/ios/form_util/test_form_activity_tab_helper.h b/components/autofill/ios/form_util/test_form_activity_tab_helper.h
index efcce4f..eaea3f9 100644
--- a/components/autofill/ios/form_util/test_form_activity_tab_helper.h
+++ b/components/autofill/ios/form_util/test_form_activity_tab_helper.h
@@ -10,18 +10,19 @@
 #include "base/macros.h"
 
 namespace web {
-struct FormActivityParams;
 class WebState;
 }  // namespace web
 
 namespace autofill {
 
+struct FormActivityParams;
+
 class TestFormActivityTabHelper {
  public:
   explicit TestFormActivityTabHelper(web::WebState* web_state);
   ~TestFormActivityTabHelper();
 
-  void FormActivityRegistered(const web::FormActivityParams& params);
+  void FormActivityRegistered(const FormActivityParams& params);
   void DocumentSubmitted(const std::string& form_name,
                          bool has_user_gesture,
                          bool form_in_main_frame);
diff --git a/components/autofill/ios/form_util/test_form_activity_tab_helper.mm b/components/autofill/ios/form_util/test_form_activity_tab_helper.mm
index 8de4c58..da07f558 100644
--- a/components/autofill/ios/form_util/test_form_activity_tab_helper.mm
+++ b/components/autofill/ios/form_util/test_form_activity_tab_helper.mm
@@ -6,8 +6,8 @@
 
 #include "base/observer_list.h"
 #include "components/autofill/ios/form_util/form_activity_observer.h"
+#include "components/autofill/ios/form_util/form_activity_params.h"
 #include "components/autofill/ios/form_util/form_activity_tab_helper.h"
-#include "ios/web/public/web_state/form_activity_params.h"
 #include "ios/web/public/web_state/web_state.h"
 
 #if !defined(__has_feature) || !__has_feature(objc_arc)
@@ -21,7 +21,7 @@
 TestFormActivityTabHelper::~TestFormActivityTabHelper() {}
 
 void TestFormActivityTabHelper::FormActivityRegistered(
-    web::FormActivityParams const& params) {
+    FormActivityParams const& params) {
   autofill::FormActivityTabHelper* form_activity_tab_helper =
       autofill::FormActivityTabHelper::GetOrCreateForWebState(web_state_);
   for (auto& observer : form_activity_tab_helper->observers_) {
diff --git a/components/consent_auditor/consent_auditor_impl.cc b/components/consent_auditor/consent_auditor_impl.cc
index d8936c2..1a250b9 100644
--- a/components/consent_auditor/consent_auditor_impl.cc
+++ b/components/consent_auditor/consent_auditor_impl.cc
@@ -69,26 +69,6 @@
   return UserConsentTypes::CONSENT_STATUS_UNSPECIFIED;
 }
 
-UserConsentSpecifics::Feature FeatureToUserConsentProtoEnum(
-    consent_auditor::Feature feature) {
-  switch (feature) {
-    case consent_auditor::Feature::CHROME_SYNC:
-      return UserConsentSpecifics::CHROME_SYNC;
-    case consent_auditor::Feature::PLAY_STORE:
-      return UserConsentSpecifics::PLAY_STORE;
-    case consent_auditor::Feature::BACKUP_AND_RESTORE:
-      return UserConsentSpecifics::BACKUP_AND_RESTORE;
-    case consent_auditor::Feature::GOOGLE_LOCATION_SERVICE:
-      return UserConsentSpecifics::GOOGLE_LOCATION_SERVICE;
-    case consent_auditor::Feature::CHROME_UNIFIED_CONSENT:
-      return UserConsentSpecifics::CHROME_UNIFIED_CONSENT;
-    case consent_auditor::Feature::ASSISTANT_ACTIVITY_CONTROL:
-      return UserConsentSpecifics::FEATURE_UNSPECIFIED;
-  }
-  NOTREACHED();
-  return UserConsentSpecifics::FEATURE_UNSPECIFIED;
-}
-
 ConsentStatus ConvertConsentStatus(
     UserConsentTypes::ConsentStatus consent_status) {
   DCHECK_NE(consent_status,
@@ -102,6 +82,20 @@
   return ConsentStatus::NOT_GIVEN;
 }
 
+std::unique_ptr<sync_pb::UserConsentSpecifics> CreateUserConsentSpecifics(
+    const std::string& account_id,
+    const std::string& locale,
+    base::Clock* clock) {
+  std::unique_ptr<sync_pb::UserConsentSpecifics> specifics =
+      std::make_unique<sync_pb::UserConsentSpecifics>();
+  specifics->set_account_id(account_id);
+  specifics->set_client_consent_time_usec(
+      clock->Now().since_origin().InMicroseconds());
+  specifics->set_locale(locale);
+
+  return specifics;
+}
+
 }  // namespace
 
 ConsentAuditorImpl::ConsentAuditorImpl(
@@ -162,19 +156,12 @@
       break;
   }
 
-  if (IsSeparateConsentTypeEnabled()) {
-    // TODO(msramek): Pass in the actual account id.
-    std::unique_ptr<sync_pb::UserConsentSpecifics> specifics =
-        ConstructUserConsentSpecifics(account_id, feature, description_grd_ids,
-                                      confirmation_grd_id, status);
-    consent_sync_bridge_->RecordConsent(std::move(specifics));
-  } else {
-    // TODO(msramek): Pass in the actual account id.
-    std::unique_ptr<sync_pb::UserEventSpecifics> specifics =
-        ConstructUserEventSpecifics(account_id, feature, description_grd_ids,
-                                    confirmation_grd_id, status);
-    user_event_service_->RecordUserEvent(std::move(specifics));
-  }
+  DCHECK(!IsSeparateConsentTypeEnabled());
+  // TODO(msramek): Pass in the actual account id.
+  std::unique_ptr<sync_pb::UserEventSpecifics> specifics =
+      ConstructUserEventSpecifics(account_id, feature, description_grd_ids,
+                                  confirmation_grd_id, status);
+  user_event_service_->RecordUserEvent(std::move(specifics));
 }
 
 std::unique_ptr<sync_pb::UserEventSpecifics>
@@ -200,100 +187,131 @@
   return specifics;
 }
 
-std::unique_ptr<sync_pb::UserConsentSpecifics>
-ConsentAuditorImpl::ConstructUserConsentSpecifics(
-    const std::string& account_id,
-    Feature feature,
-    const std::vector<int>& description_grd_ids,
-    int confirmation_grd_id,
-    ConsentStatus status) {
-  DCHECK(IsSeparateConsentTypeEnabled());
-
-  auto specifics = std::make_unique<sync_pb::UserConsentSpecifics>();
-  specifics->set_client_consent_time_usec(
-      clock_->Now().since_origin().InMicroseconds());
-  specifics->set_account_id(account_id);
-  specifics->set_feature(FeatureToUserConsentProtoEnum(feature));
-  for (int id : description_grd_ids) {
-    specifics->add_description_grd_ids(id);
-  }
-  specifics->set_confirmation_grd_id(confirmation_grd_id);
-  specifics->set_locale(app_locale_);
-  specifics->set_status(StatusToProtoEnum(status));
-  return specifics;
-}
-
 void ConsentAuditorImpl::RecordArcPlayConsent(
     const std::string& account_id,
     const ArcPlayTermsOfServiceConsent& consent) {
-  std::vector<int> description_grd_ids;
-  if (consent.consent_flow() == ArcPlayTermsOfServiceConsent::SETTING_CHANGE) {
-    for (int grd_id : consent.description_grd_ids()) {
-      description_grd_ids.push_back(grd_id);
-    }
+  if (IsSeparateConsentTypeEnabled()) {
+    std::unique_ptr<sync_pb::UserConsentSpecifics> specifics =
+        CreateUserConsentSpecifics(account_id, app_locale_, clock_);
+
+    sync_pb::UserConsentTypes::ArcPlayTermsOfServiceConsent* arc_play_consent =
+        specifics->mutable_arc_play_terms_of_service_consent();
+    arc_play_consent->CopyFrom(consent);
+    consent_sync_bridge_->RecordConsent(std::move(specifics));
   } else {
-    description_grd_ids.push_back(consent.play_terms_of_service_text_length());
+    std::vector<int> description_grd_ids;
+    if (consent.consent_flow() ==
+        ArcPlayTermsOfServiceConsent::SETTING_CHANGE) {
+      for (int grd_id : consent.description_grd_ids()) {
+        description_grd_ids.push_back(grd_id);
+      }
+    } else {
+      description_grd_ids.push_back(
+          consent.play_terms_of_service_text_length());
 
-    // TODO(markusheintz): The code below is a copy from the ARC code base. This
-    // will go away when the consent proto is set on the user consent specifics
-    // proto.
-    const std::string& hash_str = consent.play_terms_of_service_hash();
-    DCHECK_EQ(base::kSHA1Length, hash_str.size());
-    const uint8_t* hash = reinterpret_cast<const uint8_t*>(hash_str.data());
-    for (size_t i = 0; i < base::kSHA1Length; i += 4) {
-      uint32_t acc =
-          hash[i] << 24 | hash[i + 1] << 16 | hash[i + 2] << 8 | hash[i + 3];
-      description_grd_ids.push_back(static_cast<int>(acc));
+      // TODO(markusheintz): The code below is a copy from the ARC code base.
+      // This will go away when the consent proto is set on the user consent
+      // specifics proto.
+      const std::string& hash_str = consent.play_terms_of_service_hash();
+      DCHECK_EQ(base::kSHA1Length, hash_str.size());
+      const uint8_t* hash = reinterpret_cast<const uint8_t*>(hash_str.data());
+      for (size_t i = 0; i < base::kSHA1Length; i += 4) {
+        uint32_t acc =
+            hash[i] << 24 | hash[i + 1] << 16 | hash[i + 2] << 8 | hash[i + 3];
+        description_grd_ids.push_back(static_cast<int>(acc));
+      }
     }
-  }
 
-  RecordGaiaConsent(account_id, Feature::PLAY_STORE, description_grd_ids,
-                    consent.confirmation_grd_id(),
-                    ConvertConsentStatus(consent.status()));
+    RecordGaiaConsent(account_id, Feature::PLAY_STORE, description_grd_ids,
+                      consent.confirmation_grd_id(),
+                      ConvertConsentStatus(consent.status()));
+  }
 }
 
 void ConsentAuditorImpl::RecordArcGoogleLocationServiceConsent(
     const std::string& account_id,
     const UserConsentTypes::ArcGoogleLocationServiceConsent& consent) {
-  std::vector<int> description_grd_ids(consent.description_grd_ids().begin(),
-                                       consent.description_grd_ids().end());
+  if (IsSeparateConsentTypeEnabled()) {
+    std::unique_ptr<sync_pb::UserConsentSpecifics> specifics =
+        CreateUserConsentSpecifics(account_id, app_locale_, clock_);
 
-  RecordGaiaConsent(account_id, Feature::GOOGLE_LOCATION_SERVICE,
-                    description_grd_ids, consent.confirmation_grd_id(),
-                    ConvertConsentStatus(consent.status()));
+    sync_pb::UserConsentTypes::ArcGoogleLocationServiceConsent*
+        arc_google_location_service_consent =
+            specifics->mutable_arc_location_service_consent();
+    arc_google_location_service_consent->CopyFrom(consent);
+    consent_sync_bridge_->RecordConsent(std::move(specifics));
+  } else {
+    std::vector<int> description_grd_ids(consent.description_grd_ids().begin(),
+                                         consent.description_grd_ids().end());
+
+    RecordGaiaConsent(account_id, Feature::GOOGLE_LOCATION_SERVICE,
+                      description_grd_ids, consent.confirmation_grd_id(),
+                      ConvertConsentStatus(consent.status()));
+  }
 }
 
 void ConsentAuditorImpl::RecordArcBackupAndRestoreConsent(
     const std::string& account_id,
     const UserConsentTypes::ArcBackupAndRestoreConsent& consent) {
-  std::vector<int> description_grd_ids(consent.description_grd_ids().begin(),
-                                       consent.description_grd_ids().end());
+  if (IsSeparateConsentTypeEnabled()) {
+    std::unique_ptr<sync_pb::UserConsentSpecifics> specifics =
+        CreateUserConsentSpecifics(account_id, app_locale_, clock_);
 
-  RecordGaiaConsent(account_id, Feature::BACKUP_AND_RESTORE,
-                    description_grd_ids, consent.confirmation_grd_id(),
-                    ConvertConsentStatus(consent.status()));
+    sync_pb::UserConsentTypes::ArcBackupAndRestoreConsent*
+        arc_backup_and_restore_consent =
+            specifics->mutable_arc_backup_and_restore_consent();
+    arc_backup_and_restore_consent->CopyFrom(consent);
+    consent_sync_bridge_->RecordConsent(std::move(specifics));
+  } else {
+    std::vector<int> description_grd_ids(consent.description_grd_ids().begin(),
+                                         consent.description_grd_ids().end());
+
+    RecordGaiaConsent(account_id, Feature::BACKUP_AND_RESTORE,
+                      description_grd_ids, consent.confirmation_grd_id(),
+                      ConvertConsentStatus(consent.status()));
+  }
 }
 
 void ConsentAuditorImpl::RecordSyncConsent(
     const std::string& account_id,
     const UserConsentTypes::SyncConsent& consent) {
-  std::vector<int> description_grd_ids(consent.description_grd_ids().begin(),
-                                       consent.description_grd_ids().end());
+  if (IsSeparateConsentTypeEnabled()) {
+    std::unique_ptr<sync_pb::UserConsentSpecifics> specifics =
+        CreateUserConsentSpecifics(account_id, app_locale_, clock_);
 
-  RecordGaiaConsent(account_id, Feature::CHROME_SYNC, description_grd_ids,
-                    consent.confirmation_grd_id(),
-                    ConvertConsentStatus(consent.status()));
+    sync_pb::UserConsentTypes::SyncConsent* sync_consent =
+        specifics->mutable_sync_consent();
+    sync_consent->CopyFrom(consent);
+    consent_sync_bridge_->RecordConsent(std::move(specifics));
+  } else {
+    std::vector<int> description_grd_ids(consent.description_grd_ids().begin(),
+                                         consent.description_grd_ids().end());
+
+    RecordGaiaConsent(account_id, Feature::CHROME_SYNC, description_grd_ids,
+                      consent.confirmation_grd_id(),
+                      ConvertConsentStatus(consent.status()));
+  }
 }
 
 void ConsentAuditorImpl::RecordUnifiedConsent(
     const std::string& account_id,
     const sync_pb::UserConsentTypes::UnifiedConsent& consent) {
-  std::vector<int> description_grd_ids(consent.description_grd_ids().begin(),
-                                       consent.description_grd_ids().end());
+  if (IsSeparateConsentTypeEnabled()) {
+    std::unique_ptr<sync_pb::UserConsentSpecifics> specifics =
+        CreateUserConsentSpecifics(account_id, app_locale_, clock_);
 
-  RecordGaiaConsent(account_id, Feature::CHROME_UNIFIED_CONSENT,
-                    description_grd_ids, consent.confirmation_grd_id(),
-                    ConvertConsentStatus(consent.status()));
+    sync_pb::UserConsentTypes::UnifiedConsent* unified_consent =
+        specifics->mutable_unified_consent();
+    unified_consent->CopyFrom(consent);
+    consent_sync_bridge_->RecordConsent(std::move(specifics));
+  } else {
+    std::vector<int> description_grd_ids(consent.description_grd_ids().begin(),
+                                         consent.description_grd_ids().end());
+
+    RecordGaiaConsent(account_id, Feature::CHROME_UNIFIED_CONSENT,
+                      description_grd_ids, consent.confirmation_grd_id(),
+                      ConvertConsentStatus(consent.status()));
+  }
 }
 
 void ConsentAuditorImpl::RecordAssistantActivityControlConsent(
@@ -303,11 +321,7 @@
   // needed.
   if (IsSeparateConsentTypeEnabled()) {
     std::unique_ptr<sync_pb::UserConsentSpecifics> specifics =
-        std::make_unique<sync_pb::UserConsentSpecifics>();
-    specifics->set_account_id(account_id);
-    specifics->set_client_consent_time_usec(
-        clock_->Now().since_origin().InMicroseconds());
-    specifics->set_locale(app_locale_);
+        CreateUserConsentSpecifics(account_id, app_locale_, clock_);
     sync_pb::UserConsentTypes::AssistantActivityControlConsent*
         assistant_consent =
             specifics->mutable_assistant_activity_control_consent();
diff --git a/components/consent_auditor/consent_auditor_impl_unittest.cc b/components/consent_auditor/consent_auditor_impl_unittest.cc
index 5c5ea0b..c26c5a6f 100644
--- a/components/consent_auditor/consent_auditor_impl_unittest.cc
+++ b/components/consent_auditor/consent_auditor_impl_unittest.cc
@@ -360,13 +360,18 @@
   EXPECT_EQ(now.since_origin().InMicroseconds(),
             consent.client_consent_time_usec());
   EXPECT_EQ(kAccountId, consent.account_id());
-  EXPECT_EQ(UserConsentSpecifics::CHROME_SYNC, consent.feature());
-  EXPECT_EQ(3, consent.description_grd_ids_size());
-  EXPECT_EQ(kDescriptionMessageIds[0], consent.description_grd_ids(0));
-  EXPECT_EQ(kDescriptionMessageIds[1], consent.description_grd_ids(1));
-  EXPECT_EQ(kDescriptionMessageIds[2], consent.description_grd_ids(2));
-  EXPECT_EQ(kConfirmationMessageId, consent.confirmation_grd_id());
   EXPECT_EQ(kCurrentAppLocale, consent.locale());
+
+  EXPECT_TRUE(consent.has_sync_consent());
+  const SyncConsent& actual_sync_consent = consent.sync_consent();
+  EXPECT_EQ(3, actual_sync_consent.description_grd_ids_size());
+  EXPECT_EQ(kDescriptionMessageIds[0],
+            actual_sync_consent.description_grd_ids(0));
+  EXPECT_EQ(kDescriptionMessageIds[1],
+            actual_sync_consent.description_grd_ids(1));
+  EXPECT_EQ(kDescriptionMessageIds[2],
+            actual_sync_consent.description_grd_ids(2));
+  EXPECT_EQ(kConfirmationMessageId, actual_sync_consent.confirmation_grd_id());
 }
 
 TEST_F(ConsentAuditorImplTest, RecordArcPlayConsentRevocation) {
@@ -405,14 +410,22 @@
   UserConsentSpecifics consent = consents[0];
 
   EXPECT_EQ(kAccountId, consent.account_id());
-  EXPECT_EQ(UserConsentTypes::NOT_GIVEN, consent.status());
-  EXPECT_EQ(UserConsentSpecifics::PLAY_STORE, consent.feature());
-  EXPECT_EQ(3, consent.description_grd_ids_size());
-  EXPECT_EQ(kDescriptionMessageIds[0], consent.description_grd_ids(0));
-  EXPECT_EQ(kDescriptionMessageIds[1], consent.description_grd_ids(1));
-  EXPECT_EQ(kDescriptionMessageIds[2], consent.description_grd_ids(2));
-  EXPECT_EQ(kConfirmationMessageId, consent.confirmation_grd_id());
   EXPECT_EQ(kCurrentAppLocale, consent.locale());
+
+  EXPECT_TRUE(consent.has_arc_play_terms_of_service_consent());
+  const ArcPlayTermsOfServiceConsent& actual_play_consent =
+      consent.arc_play_terms_of_service_consent();
+  EXPECT_EQ(UserConsentTypes::NOT_GIVEN, actual_play_consent.status());
+  EXPECT_EQ(ArcPlayTermsOfServiceConsent::SETTING_CHANGE,
+            actual_play_consent.consent_flow());
+  EXPECT_EQ(3, actual_play_consent.description_grd_ids_size());
+  EXPECT_EQ(kDescriptionMessageIds[0],
+            actual_play_consent.description_grd_ids(0));
+  EXPECT_EQ(kDescriptionMessageIds[1],
+            actual_play_consent.description_grd_ids(1));
+  EXPECT_EQ(kDescriptionMessageIds[2],
+            actual_play_consent.description_grd_ids(2));
+  EXPECT_EQ(kConfirmationMessageId, actual_play_consent.confirmation_grd_id());
 }
 
 TEST_F(ConsentAuditorImplTest, RecordArcPlayConsent) {
@@ -456,18 +469,20 @@
   UserConsentSpecifics consent = consents[0];
 
   EXPECT_EQ(kAccountId, consent.account_id());
-  EXPECT_EQ(UserConsentSpecifics::PLAY_STORE, consent.feature());
-
-  EXPECT_EQ(6, consent.description_grd_ids_size());
-  EXPECT_EQ(7, consent.description_grd_ids(0));
-  EXPECT_EQ(static_cast<int>(0x2fd4e1c6), consent.description_grd_ids(1));
-  EXPECT_EQ(static_cast<int>(0x7a2d28fc), consent.description_grd_ids(2));
-  EXPECT_EQ(static_cast<int>(0xed849ee1), consent.description_grd_ids(3));
-  EXPECT_EQ(static_cast<int>(0xbb76e739), consent.description_grd_ids(4));
-  EXPECT_EQ(static_cast<int>(0x1b93eb12), consent.description_grd_ids(5));
-
-  EXPECT_EQ(kConfirmationMessageId, consent.confirmation_grd_id());
   EXPECT_EQ(kCurrentAppLocale, consent.locale());
+
+  EXPECT_TRUE(consent.has_arc_play_terms_of_service_consent());
+  const ArcPlayTermsOfServiceConsent& actual_play_consent =
+      consent.arc_play_terms_of_service_consent();
+
+  EXPECT_EQ(7, actual_play_consent.play_terms_of_service_text_length());
+  EXPECT_EQ(std::string(play_tos_hash, base::kSHA1Length),
+            actual_play_consent.play_terms_of_service_hash());
+
+  EXPECT_EQ(kConfirmationMessageId, actual_play_consent.confirmation_grd_id());
+  EXPECT_EQ(ArcPlayTermsOfServiceConsent::SETUP,
+            actual_play_consent.consent_flow());
+  EXPECT_EQ(UserConsentTypes::GIVEN, actual_play_consent.status());
 }
 
 TEST_F(ConsentAuditorImplTest, ShouldReturnNoSyncDelegateWhenNoBridge) {
diff --git a/components/feed/content/BUILD.gn b/components/feed/content/BUILD.gn
index 86059fa..64d2d386 100644
--- a/components/feed/content/BUILD.gn
+++ b/components/feed/content/BUILD.gn
@@ -36,6 +36,7 @@
     ":feed_content",
     "//base",
     "//base/test:test_support",
+    "//components/offline_pages/core",
     "//components/offline_pages/core:test_support",
     "//components/offline_pages/core/prefetch:test_support",
     "//testing/gtest:gtest",
diff --git a/components/feed/content/feed_offline_host.cc b/components/feed/content/feed_offline_host.cc
index 0ab6347d..256df3eb 100644
--- a/components/feed/content/feed_offline_host.cc
+++ b/components/feed/content/feed_offline_host.cc
@@ -4,10 +4,79 @@
 
 #include "components/feed/content/feed_offline_host.h"
 
+#include <utility>
+
+#include "base/bind.h"
+#include "base/hash.h"
+#include "base/metrics/histogram_macros.h"
+#include "components/feed/core/feed_scheduler_host.h"
+#include "components/offline_pages/core/prefetch/prefetch_service.h"
 #include "url/gurl.h"
 
 namespace feed {
 
+namespace {
+
+// |url| is always set. Sometimes |original_url| is set. If |original_url| is
+// set it is returned by this method, otherwise fall back to |url|.
+const GURL& PreferOriginal(const offline_pages::OfflinePageItem& item) {
+  return item.original_url.is_empty() ? item.url : item.original_url;
+}
+
+// Aggregates multiple callbacks from OfflinePageModel, storing the offline url.
+// When all callbacks have been invoked, tracked by ref counting, then
+// |on_completeion_| is finally invoked, sending all results together.
+class CallbackAggregator : public base::RefCounted<CallbackAggregator> {
+ public:
+  using ReportStatusCallback =
+      base::OnceCallback<void(std::vector<std::string>)>;
+  using CacheIdCallback =
+      base::RepeatingCallback<void(const std::string&, int64_t)>;
+
+  CallbackAggregator(ReportStatusCallback on_completion,
+                     CacheIdCallback on_each_result)
+      : on_completion_(std::move(on_completion)),
+        on_each_result_(std::move(on_each_result)),
+        start_time_(base::Time::Now()) {}
+
+  void OnGetPages(const std::vector<offline_pages::OfflinePageItem>& pages) {
+    if (!pages.empty()) {
+      offline_pages::OfflinePageItem newest =
+          *std::max_element(pages.begin(), pages.end(), [](auto lhs, auto rhs) {
+            return lhs.creation_time < rhs.creation_time;
+          });
+      const std::string& url = PreferOriginal(newest).spec();
+      urls_.push_back(url);
+      on_each_result_.Run(url, newest.offline_id);
+    }
+  }
+
+ private:
+  friend class base::RefCounted<CallbackAggregator>;
+
+  ~CallbackAggregator() {
+    base::TimeDelta duration = base::Time::Now() - start_time_;
+    UMA_HISTOGRAM_TIMES("Feed.Offline.GetStatusDuration", duration);
+    std::move(on_completion_).Run(std::move(urls_));
+  }
+
+  // To be called once all callbacks are run or destroyed.
+  ReportStatusCallback on_completion_;
+
+  // The urls of the offlined pages seen so far. Ultimately will be given to
+  // |on_completeion_|.
+  std::vector<std::string> urls_;
+
+  // Is not run if there are no results for a given url.
+  CacheIdCallback on_each_result_;
+
+  // The time the aggregator was created, before any requests were sent to the
+  // OfflinePageModel.
+  base::Time start_time_;
+};
+
+}  //  namespace
+
 FeedOfflineHost::FeedOfflineHost(
     offline_pages::OfflinePageModel* offline_page_model,
     offline_pages::PrefetchService* prefetch_service,
@@ -26,14 +95,27 @@
 
 FeedOfflineHost::~FeedOfflineHost() = default;
 
-base::Optional<int64_t> FeedOfflineHost::GetOfflineId(std::string url) {
-  return {};
+base::Optional<int64_t> FeedOfflineHost::GetOfflineId(const std::string& url) {
+  auto iter = url_hash_to_id_.find(base::Hash(url));
+  return iter == url_hash_to_id_.end() ? base::Optional<int64_t>()
+                                       : base::Optional<int64_t>(iter->second);
 }
 
 void FeedOfflineHost::GetOfflineStatus(
     std::vector<std::string> urls,
-    base::OnceCallback<void(const std::vector<std::string>&)> callback) {
-  // TODO(skym): Call OfflinePageModel::GetPagesByURL() for each url.
+    base::OnceCallback<void(std::vector<std::string>)> callback) {
+  UMA_HISTOGRAM_EXACT_LINEAR("Feed.Offline.GetStatusCount", urls.size(), 50);
+
+  scoped_refptr<CallbackAggregator> aggregator =
+      base::MakeRefCounted<CallbackAggregator>(
+          std::move(callback),
+          base::BindRepeating(&FeedOfflineHost::CacheOfflinePageAndId,
+                              weak_ptr_factory_.GetWeakPtr()));
+
+  for (std::string url : urls) {
+    offline_page_model_->GetPagesByURL(
+        GURL(url), base::BindOnce(&CallbackAggregator::OnGetPages, aggregator));
+  }
 }
 
 void FeedOfflineHost::OnContentRemoved(std::vector<std::string> urls) {
@@ -78,4 +160,9 @@
   // TODO(skym): Call into bridge callback.
 }
 
+void FeedOfflineHost::CacheOfflinePageAndId(const std::string& url,
+                                            int64_t id) {
+  url_hash_to_id_[base::Hash(url)] = id;
+}
+
 }  // namespace feed
diff --git a/components/feed/content/feed_offline_host.h b/components/feed/content/feed_offline_host.h
index 09f192f1..6816a54 100644
--- a/components/feed/content/feed_offline_host.h
+++ b/components/feed/content/feed_offline_host.h
@@ -9,6 +9,7 @@
 #include <vector>
 
 #include "base/callback.h"
+#include "base/containers/flat_map.h"
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/optional.h"
@@ -43,13 +44,13 @@
   // receive a false negative. Additionally, since the host tracks pages by
   // hashing, there's also a small chance that the host erroneously returns an
   // id for a page that is not offlined.
-  base::Optional<int64_t> GetOfflineId(std::string url);
+  base::Optional<int64_t> GetOfflineId(const std::string& url);
 
   // Asynchronously fetches offline status for the given URLs. Any pages that
   // are currently offlined will be remembered by the FeedOfflineHost.
   void GetOfflineStatus(
       std::vector<std::string> urls,
-      base::OnceCallback<void(const std::vector<std::string>&)> callback);
+      base::OnceCallback<void(std::vector<std::string>)> callback);
 
   // Should be called from Feed any time the user manually removes articles or
   // groupings of articles. Propagates the signal to Prefetch.
@@ -80,6 +81,10 @@
       override;
 
  private:
+  // Stores the given record in |url_hash_to_id_|. If there's a conflict, the
+  // new id will overwrite the old value.
+  void CacheOfflinePageAndId(const std::string& url, int64_t id);
+
   // The following objects all outlive us, so it is safe to hold raw pointers to
   // them. This is guaranteed by the FeedHostServiceFactory.
   offline_pages::OfflinePageModel* offline_page_model_;
@@ -88,6 +93,12 @@
   base::RepeatingClosure on_suggestion_consumed_;
   base::RepeatingClosure on_suggestions_shown_;
 
+  // Only offlined pages that have passed through the host are stored. If there
+  // are ever no listeners to the offline host logic and OnNoListeners() is
+  // called this map is cleared. The key is the hash of the url, and the value
+  // is the offline id for the given page.
+  base::flat_map<uint32_t, int64_t> url_hash_to_id_;
+
   base::WeakPtrFactory<FeedOfflineHost> weak_ptr_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(FeedOfflineHost);
diff --git a/components/feed/content/feed_offline_host_unittest.cc b/components/feed/content/feed_offline_host_unittest.cc
index a1c9ba2..eb2e93f 100644
--- a/components/feed/content/feed_offline_host_unittest.cc
+++ b/components/feed/content/feed_offline_host_unittest.cc
@@ -4,21 +4,86 @@
 
 #include "components/feed/content/feed_offline_host.h"
 
+#include <algorithm>
+#include <map>
 #include <memory>
+#include <utility>
 
 #include "base/bind.h"
+#include "base/task/post_task.h"
+#include "base/test/scoped_task_environment.h"
+#include "base/threading/thread_task_runner_handle.h"
+#include "components/offline_pages/core/offline_page_item.h"
+#include "components/offline_pages/core/offline_page_types.h"
 #include "components/offline_pages/core/prefetch/stub_prefetch_service.h"
 #include "components/offline_pages/core/stub_offline_page_model.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace feed {
 
+namespace {
+
+const char kUrl1[] = "https://www.one.com/";
+const char kUrl2[] = "https://www.two.com/";
+const char kUrl3[] = "https://www.three.com/";
+
+class TestOfflinePageModel : public offline_pages::StubOfflinePageModel {
+ public:
+  void AddOfflinedPage(const std::string& url,
+                       const std::string& original_url,
+                       int64_t offline_id,
+                       base::Time creation_time) {
+    offline_pages::OfflinePageItem item;
+    item.url = GURL(url);
+    item.original_url = GURL(original_url);
+    item.offline_id = offline_id;
+    item.creation_time = creation_time;
+    url_to_offline_page_item_.emplace(url, item);
+    if (!original_url.empty()) {
+      url_to_offline_page_item_.emplace(original_url, item);
+    }
+  }
+
+  void AddOfflinedPage(const std::string& url, int64_t offline_id) {
+    AddOfflinedPage(url, "", offline_id, base::Time());
+  }
+
+ private:
+  void GetPagesByURL(
+      const GURL& url,
+      offline_pages::MultipleOfflinePageItemCallback callback) override {
+    auto iter = url_to_offline_page_item_.equal_range(url.spec());
+    std::vector<offline_pages::OfflinePageItem> ret;
+    ret.resize(std::distance(iter.first, iter.second));
+    std::transform(iter.first, iter.second, ret.begin(),
+                   [](auto pair) { return pair.second; });
+
+    base::ThreadTaskRunnerHandle::Get()->PostTask(
+        FROM_HERE, base::BindOnce(std::move(callback), std::move(ret)));
+  }
+
+  // Maps URLs to offline_pages::OfflinePageItem. Items with both |urls| and
+  // |original_url| will be inserted at both locations in the multimap.
+  std::multimap<std::string, offline_pages::OfflinePageItem>
+      url_to_offline_page_item_;
+};
+
+void CopyResults(std::vector<std::string>* actual,
+                 std::vector<std::string> result) {
+  *actual = result;
+}
+
+}  // namespace
+
 class FeedOfflineHostTest : public ::testing::Test {
  public:
+  TestOfflinePageModel* offline_page_model() { return &offline_page_model_; }
   FeedOfflineHost* host() { return host_.get(); }
   int get_suggestion_consumed_count() { return suggestion_consumed_count_; }
   int get_suggestions_shown_count() { return suggestions_shown_count_; }
 
+  void RunUntilIdle() { scoped_task_environment_.RunUntilIdle(); }
+
  protected:
   FeedOfflineHostTest() {
     host_ = std::make_unique<FeedOfflineHost>(
@@ -32,7 +97,8 @@
   void OnSuggestionConsumed() { ++suggestion_consumed_count_; }
   void OnSuggestionsShown() { ++suggestions_shown_count_; }
 
-  offline_pages::StubOfflinePageModel offline_page_model_;
+  base::test::ScopedTaskEnvironment scoped_task_environment_;
+  TestOfflinePageModel offline_page_model_;
   offline_pages::StubPrefetchService prefetch_service_;
   std::unique_ptr<FeedOfflineHost> host_;
   int suggestion_consumed_count_ = 0;
@@ -50,11 +116,78 @@
 
 TEST_F(FeedOfflineHostTest, OnSuggestionsShown) {
   EXPECT_EQ(0, get_suggestions_shown_count());
-  host()->ReportArticleViewed(GURL("https://www.one.com"));
+  host()->ReportArticleViewed(GURL(kUrl1));
   EXPECT_EQ(1, get_suggestions_shown_count());
-  host()->ReportArticleViewed(GURL("https://www.one.com"));
+  host()->ReportArticleViewed(GURL(kUrl1));
   EXPECT_EQ(2, get_suggestions_shown_count());
   EXPECT_EQ(0, get_suggestion_consumed_count());
 }
 
+TEST_F(FeedOfflineHostTest, GetOfflineStatusEmpty) {
+  std::vector<std::string> actual;
+  host()->GetOfflineStatus({}, base::BindOnce(&CopyResults, &actual));
+  RunUntilIdle();
+
+  EXPECT_EQ(0U, actual.size());
+}
+
+TEST_F(FeedOfflineHostTest, GetOfflineStatusMiss) {
+  offline_page_model()->AddOfflinedPage(kUrl1, 4);
+
+  std::vector<std::string> actual;
+  host()->GetOfflineStatus({kUrl2}, base::BindOnce(&CopyResults, &actual));
+  RunUntilIdle();
+
+  EXPECT_EQ(0U, actual.size());
+  EXPECT_FALSE(host()->GetOfflineId(kUrl1).has_value());
+  EXPECT_FALSE(host()->GetOfflineId(kUrl2).has_value());
+}
+
+TEST_F(FeedOfflineHostTest, GetOfflineStatusHit) {
+  offline_page_model()->AddOfflinedPage(kUrl1, 4);
+  offline_page_model()->AddOfflinedPage(kUrl2, 5);
+  offline_page_model()->AddOfflinedPage(kUrl3, 6);
+
+  std::vector<std::string> actual;
+  host()->GetOfflineStatus({kUrl1, kUrl2},
+                           base::BindOnce(&CopyResults, &actual));
+
+  EXPECT_EQ(0U, actual.size());
+  RunUntilIdle();
+
+  EXPECT_EQ(2U, actual.size());
+  EXPECT_TRUE(actual[0] == kUrl1 || actual[1] == kUrl1);
+  EXPECT_TRUE(actual[0] == kUrl2 || actual[1] == kUrl2);
+  EXPECT_EQ(host()->GetOfflineId(kUrl1).value(), 4);
+  EXPECT_EQ(host()->GetOfflineId(kUrl2).value(), 5);
+  EXPECT_FALSE(host()->GetOfflineId(kUrl3).has_value());
+}
+
+TEST_F(FeedOfflineHostTest, GetOfflineIdOriginalUrl) {
+  offline_page_model()->AddOfflinedPage(kUrl1, kUrl2, 4, base::Time());
+
+  std::vector<std::string> actual;
+  host()->GetOfflineStatus({kUrl2}, base::BindOnce(&CopyResults, &actual));
+  RunUntilIdle();
+
+  EXPECT_EQ(1U, actual.size());
+  EXPECT_EQ(kUrl2, actual[0]);
+  EXPECT_FALSE(host()->GetOfflineId(kUrl1).has_value());
+  EXPECT_EQ(host()->GetOfflineId(kUrl2).value(), 4);
+}
+
+TEST_F(FeedOfflineHostTest, GetOfflineIdNewer) {
+  offline_page_model()->AddOfflinedPage(kUrl1, "", 4, base::Time());
+  offline_page_model()->AddOfflinedPage(
+      kUrl1, "", 5, base::Time() + base::TimeDelta::FromHours(1));
+
+  std::vector<std::string> actual;
+  host()->GetOfflineStatus({kUrl1}, base::BindOnce(&CopyResults, &actual));
+  RunUntilIdle();
+
+  EXPECT_EQ(1U, actual.size());
+  EXPECT_EQ(kUrl1, actual[0]);
+  EXPECT_EQ(host()->GetOfflineId(kUrl1).value(), 5);
+}
+
 }  // namespace feed
diff --git a/components/grpc_support/bidirectional_stream_unittest.cc b/components/grpc_support/bidirectional_stream_unittest.cc
index 24f9f7a..4db647a 100644
--- a/components/grpc_support/bidirectional_stream_unittest.cc
+++ b/components/grpc_support/bidirectional_stream_unittest.cc
@@ -13,6 +13,7 @@
 #include "base/macros.h"
 #include "base/strings/strcat.h"
 #include "base/synchronization/waitable_event.h"
+#include "build/build_config.h"
 #include "components/grpc_support/include/bidirectional_stream_c.h"
 #include "components/grpc_support/test/get_stream_engine.h"
 #include "net/base/net_errors.h"
@@ -580,7 +581,16 @@
   bidirectional_stream_destroy(test.stream);
 }
 
-TEST_P(BidirectionalStreamTest, StreamFailBeforeReadIsExecutedOnNetworkThread) {
+// TODO(https://crbug.com/880474): This test is flaky on fuchsia_x64 builder.
+#if defined(OS_FUCHSIA)
+#define MAYBE_StreamFailBeforeReadIsExecutedOnNetworkThread \
+  DISABLED_StreamFailBeforeReadIsExecutedOnNetworkThread
+#else
+#define MAYBE_StreamFailBeforeReadIsExecutedOnNetworkThread \
+  StreamFailBeforeReadIsExecutedOnNetworkThread
+#endif
+TEST_P(BidirectionalStreamTest,
+       MAYBE_StreamFailBeforeReadIsExecutedOnNetworkThread) {
   class CustomTestBidirectionalStreamCallback
       : public TestBidirectionalStreamCallback {
     bool MaybeCancel(bidirectional_stream* stream, ResponseStep step) override {
diff --git a/components/network_session_configurator/browser/network_session_configurator.cc b/components/network_session_configurator/browser/network_session_configurator.cc
index 070e07c6..fffb2fa 100644
--- a/components/network_session_configurator/browser/network_session_configurator.cc
+++ b/components/network_session_configurator/browser/network_session_configurator.cc
@@ -4,6 +4,7 @@
 
 #include "components/network_session_configurator/browser/network_session_configurator.h"
 
+#include <limits>
 #include <map>
 #include <unordered_set>
 #include <utility>
@@ -13,6 +14,7 @@
 #include "base/feature_list.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_macros.h"
+#include "base/rand_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_piece.h"
 #include "base/strings/string_split.h"
@@ -24,6 +26,7 @@
 #include "net/base/host_mapping_rules.h"
 #include "net/http/http_stream_factory.h"
 #include "net/quic/quic_utils_chromium.h"
+#include "net/spdy/spdy_session_pool.h"
 #include "net/third_party/quic/core/quic_packets.h"
 #include "net/third_party/spdy/core/spdy_protocol.h"
 
@@ -123,7 +126,36 @@
     params->enable_http2 = false;
     return;
   }
+
+  // After parsing initial settings, optionally add a setting with reserved
+  // identifier to "grease" settings, see
+  // https://tools.ietf.org/html/draft-bishop-httpbis-grease-00.
   params->http2_settings = GetHttp2Settings(http2_trial_params);
+  if (GetVariationParam(http2_trial_params, "http2_grease_settings") ==
+      "true") {
+    spdy::SpdySettingsId id = 0x0a0a + 0x1000 * base::RandGenerator(0xf + 1) +
+                              0x0010 * base::RandGenerator(0xf + 1);
+    uint32_t value = base::RandGenerator(
+        static_cast<uint64_t>(std::numeric_limits<uint32_t>::max()) + 1);
+    params->http2_settings.insert(std::make_pair(id, value));
+  }
+
+  // Optionally define a frame of reserved type to "grease" frame types, see
+  // https://tools.ietf.org/html/draft-bishop-httpbis-grease-00.
+  if (GetVariationParam(http2_trial_params, "http2_grease_frame_type") ==
+      "true") {
+    const uint8_t type = 0x0b + 0x1f * base::RandGenerator(8);
+    const uint8_t flags =
+        base::RandGenerator(std::numeric_limits<uint8_t>::max() + 1);
+    const size_t length = base::RandGenerator(7);
+    // RandBytesAsString() does not support zero length.
+    const std::string payload =
+        (length > 0) ? base::RandBytesAsString(length) : std::string();
+    params->greased_http2_frame =
+        base::Optional<net::SpdySessionPool::GreasedHttp2Frame>(
+            {type, flags, payload});
+  }
+
   params->enable_websocket_over_http2 =
       ConfigureWebsocketOverHttp2(command_line, http2_trial_params);
 }
diff --git a/components/network_session_configurator/browser/network_session_configurator_unittest.cc b/components/network_session_configurator/browser/network_session_configurator_unittest.cc
index f6acf0b..89c9f46d 100644
--- a/components/network_session_configurator/browser/network_session_configurator_unittest.cc
+++ b/components/network_session_configurator/browser/network_session_configurator_unittest.cc
@@ -64,6 +64,7 @@
 
   EXPECT_TRUE(params_.enable_http2);
   EXPECT_TRUE(params_.http2_settings.empty());
+  EXPECT_FALSE(params_.greased_http2_frame);
   EXPECT_FALSE(params_.enable_websocket_over_http2);
 
   EXPECT_FALSE(params_.enable_quic);
@@ -796,6 +797,37 @@
   EXPECT_TRUE(params_.quic_headers_include_h2_stream_dependency);
 }
 
+TEST_F(NetworkSessionConfiguratorTest, Http2GreaseSettings) {
+  std::map<std::string, std::string> field_trial_params;
+  field_trial_params["http2_grease_settings"] = "true";
+  variations::AssociateVariationParams("HTTP2", "Enabled", field_trial_params);
+  base::FieldTrialList::CreateFieldTrial("HTTP2", "Enabled");
+
+  ParseFieldTrials();
+
+  bool greased_setting_found = false;
+  for (const auto& setting : params_.http2_settings) {
+    if ((setting.first & 0x0f0f) == 0x0a0a) {
+      greased_setting_found = true;
+      break;
+    }
+  }
+  EXPECT_TRUE(greased_setting_found);
+}
+
+TEST_F(NetworkSessionConfiguratorTest, Http2GreaseFrameType) {
+  std::map<std::string, std::string> field_trial_params;
+  field_trial_params["http2_grease_frame_type"] = "true";
+  variations::AssociateVariationParams("HTTP2", "Enabled", field_trial_params);
+  base::FieldTrialList::CreateFieldTrial("HTTP2", "Enabled");
+
+  ParseFieldTrials();
+
+  ASSERT_TRUE(params_.greased_http2_frame);
+  const uint8_t frame_type = params_.greased_http2_frame.value().type;
+  EXPECT_EQ(0x0b, frame_type % 0x1f);
+}
+
 TEST_F(NetworkSessionConfiguratorTest,
        WebsocketOverHttp2EnabledFromCommandLine) {
   base::CommandLine command_line(base::CommandLine::NO_PROGRAM);
diff --git a/components/omnibox/browser/autocomplete_match_type.cc b/components/omnibox/browser/autocomplete_match_type.cc
index 18e4e5db..cd315dc 100644
--- a/components/omnibox/browser/autocomplete_match_type.cc
+++ b/components/omnibox/browser/autocomplete_match_type.cc
@@ -60,9 +60,34 @@
 }
 
 // static
+base::string16 AddTabSwitchLabelTextIfNecessary(
+    base::string16 base_message,
+    bool has_tab_match,
+    bool is_tab_switch_button_focused,
+    int* label_prefix_length) {
+  if (!has_tab_match) {
+    return base_message;
+  }
+
+  if (is_tab_switch_button_focused) {
+    const int kButtonMessage = IDS_ACC_TAB_SWITCH_BUTTON_FOCUSED_PREFIX;
+    if (label_prefix_length) {
+      const base::string16 sentinal =
+          base::WideToUTF16(kAccessibilityLabelPrefixEndSentinal);
+      *label_prefix_length += AccessibilityLabelPrefixLength(
+          l10n_util::GetStringFUTF16(kButtonMessage, sentinal));
+    }
+    return l10n_util::GetStringFUTF16(kButtonMessage, base_message);
+  }
+
+  return l10n_util::GetStringFUTF16(IDS_ACC_TAB_SWITCH_SUFFIX, base_message);
+}
+
+// static
 base::string16 AutocompleteMatchType::ToAccessibilityLabel(
     const AutocompleteMatch& match,
     const base::string16& match_text,
+    bool is_tab_switch_button_focused,
     int* label_prefix_length) {
   // Types with a message ID of zero get |text| returned as-is.
   static constexpr int message_ids[] = {
@@ -109,10 +134,9 @@
 
   int message = message_ids[match.type];
   if (!message) {
-    if (!match.has_tab_match)
-      return match_text;
-    else
-      return l10n_util::GetStringFUTF16(IDS_ACC_TAB_SWITCH_SUFFIX, match_text);
+    return AddTabSwitchLabelTextIfNecessary(match_text, match.has_tab_match,
+                                            is_tab_switch_button_focused,
+                                            label_prefix_length);
   }
 
   const base::string16 sentinal =
@@ -169,10 +193,10 @@
       has_description
           ? l10n_util::GetStringFUTF16(message, match_text, description)
           : l10n_util::GetStringFUTF16(message, match_text);
-  if (!match.has_tab_match)
-    return base_message;
-  else
-    return l10n_util::GetStringFUTF16(IDS_ACC_TAB_SWITCH_SUFFIX, base_message);
+
+  return AddTabSwitchLabelTextIfNecessary(base_message, match.has_tab_match,
+                                          is_tab_switch_button_focused,
+                                          label_prefix_length);
 }
 
 // static
@@ -181,9 +205,13 @@
     const base::string16& match_text,
     size_t match_index,
     size_t total_matches,
+    bool is_tab_switch_button_focused,
     int* label_prefix_length) {
-  base::string16 result =
-      ToAccessibilityLabel(match, match_text, label_prefix_length);
+  base::string16 result = ToAccessibilityLabel(
+      match, match_text, is_tab_switch_button_focused, label_prefix_length);
+
+  if (is_tab_switch_button_focused)
+    return result;  // Don't add "n of m" positional info when button focused.
 
   return l10n_util::GetStringFUTF16(IDS_ACC_AUTOCOMPLETE_N_OF_M, result,
                                     base::IntToString16(match_index + 1),
diff --git a/components/omnibox/browser/autocomplete_match_type.h b/components/omnibox/browser/autocomplete_match_type.h
index 9c0684596..d9441d9 100644
--- a/components/omnibox/browser/autocomplete_match_type.h
+++ b/components/omnibox/browser/autocomplete_match_type.h
@@ -82,11 +82,13 @@
       const base::string16& match_text,
       size_t match_index,
       size_t total_matches,
+      bool is_tab_switch_button_focused,
       int* label_prefix_length = nullptr);
   // This version returns a plain label without ", n of m" positional info:
   static base::string16 ToAccessibilityLabel(
       const AutocompleteMatch& match,
       const base::string16& match_text,
+      bool is_tab_switch_button_focused,
       int* label_prefix_length = nullptr);
 };
 
diff --git a/components/omnibox/browser/autocomplete_match_type_unittest.cc b/components/omnibox/browser/autocomplete_match_type_unittest.cc
index 78fc66e..ce91824 100644
--- a/components/omnibox/browser/autocomplete_match_type_unittest.cc
+++ b/components/omnibox/browser/autocomplete_match_type_unittest.cc
@@ -21,13 +21,15 @@
   match.type = AutocompleteMatchType::URL_WHAT_YOU_TYPED;
   match.description = kTestTitle;
   EXPECT_EQ(kTestUrl + base::UTF8ToUTF16(", 2 of 9"),
-            AutocompleteMatchType::ToAccessibilityLabel(match, kTestUrl, 1, 9));
+            AutocompleteMatchType::ToAccessibilityLabel(match, kTestUrl, 1, 9,
+                                                        false));
 
   // Decorated with title and match type.
   match.type = AutocompleteMatchType::HISTORY_URL;
   EXPECT_EQ(kTestTitle + base::UTF8ToUTF16(" ") + kTestUrl +
                 base::UTF8ToUTF16(" location from history, 2 of 3"),
-            AutocompleteMatchType::ToAccessibilityLabel(match, kTestUrl, 1, 3));
+            AutocompleteMatchType::ToAccessibilityLabel(match, kTestUrl, 1, 3,
+                                                        false));
 }
 
 TEST(AutocompleteMatchTypeTest, AccessibilityLabelSearch) {
@@ -37,8 +39,9 @@
   AutocompleteMatch match;
   match.type = AutocompleteMatchType::SEARCH_WHAT_YOU_TYPED;
   match.description = kSearchDesc;
-  EXPECT_EQ(kSearch + base::UTF8ToUTF16(" search, 6 of 8"),
-            AutocompleteMatchType::ToAccessibilityLabel(match, kSearch, 5, 8));
+  EXPECT_EQ(
+      kSearch + base::UTF8ToUTF16(" search, 6 of 8"),
+      AutocompleteMatchType::ToAccessibilityLabel(match, kSearch, 5, 8, false));
 }
 
 namespace {
@@ -72,7 +75,8 @@
   ASSERT_TRUE(ParseAnswer(answer_json, &answer));
   match.answer = answer;
 
-  EXPECT_EQ(kSearch + base::UTF8ToUTF16(
-                          ", answer, sunny with a chance of hail, 4 of 6"),
-            AutocompleteMatchType::ToAccessibilityLabel(match, kSearch, 3, 6));
+  EXPECT_EQ(
+      kSearch +
+          base::UTF8ToUTF16(", answer, sunny with a chance of hail, 4 of 6"),
+      AutocompleteMatchType::ToAccessibilityLabel(match, kSearch, 3, 6, false));
 }
diff --git a/components/omnibox/browser/autocomplete_result.cc b/components/omnibox/browser/autocomplete_result.cc
index 475ad8c..9d77688 100644
--- a/components/omnibox/browser/autocomplete_result.cc
+++ b/components/omnibox/browser/autocomplete_result.cc
@@ -29,6 +29,14 @@
 #include "third_party/metrics_proto/omnibox_input_type.pb.h"
 #include "ui/base/l10n/l10n_util.h"
 
+struct MatchGURLHash {
+  // The |bool| is whether the match is a calculator suggestion. We want them
+  // compare differently against other matches with the same URL.
+  size_t operator()(const std::pair<GURL, bool>& p) const {
+    return std::hash<std::string>()(p.first.spec()) + p.second;
+  }
+};
+
 // A match attribute when a default match's score has been boosted
 // with a higher scoring non-default match.
 static const char kScoreBoostedFrom[] = "score_boosted_from";
@@ -356,16 +364,20 @@
 void AutocompleteResult::SortAndDedupMatches(
     metrics::OmniboxEventProto::PageClassification page_classification,
     ACMatches* matches) {
-  // Group matches by stripped URL.
-  std::unordered_map<GURL, std::list<ACMatches::iterator>, MatchGURLHash>
+  // Group matches by stripped URL and whether it's a calculator suggestion.
+  std::unordered_map<std::pair<GURL, bool>, std::list<ACMatches::iterator>,
+                     MatchGURLHash>
       url_to_matches;
-  for (auto i = matches->begin(); i != matches->end(); ++i)
-    url_to_matches[i->stripped_destination_url].push_back(i);
+  for (auto i = matches->begin(); i != matches->end(); ++i) {
+    std::pair<GURL, bool> p = GetMatchComparisonFields(*i);
+    url_to_matches[p].push_back(i);
+  }
   CompareWithDemoteByType<AutocompleteMatch> compare_demote_by_type(
       page_classification);
   // Find best default, and non-default, match in each group.
   for (auto& group : url_to_matches) {
-    const GURL& gurl = group.first;
+    const auto& p = group.first;
+    const GURL& gurl = p.first;
     // The list of matches whose URL are equivalent.
     auto& duplicate_matches = group.second;
     if (gurl.is_empty() || duplicate_matches.size() == 1)
@@ -413,8 +425,9 @@
       std::remove_if(
           matches->begin(), matches->end(),
           [&url_to_matches](const AutocompleteMatch& m) {
+            std::pair<GURL, bool> p = GetMatchComparisonFields(m);
             return !m.stripped_destination_url.is_empty() &&
-                   &(*url_to_matches[m.stripped_destination_url].front()) != &m;
+                   &(*url_to_matches[p].front()) != &m;
           }),
       matches->end());
 }
@@ -561,3 +574,9 @@
     }
   }
 }
+
+std::pair<GURL, bool> AutocompleteResult::GetMatchComparisonFields(
+    const AutocompleteMatch& match) {
+  return std::make_pair(match.stripped_destination_url,
+                        match.type == AutocompleteMatchType::CALCULATOR);
+}
diff --git a/components/omnibox/browser/autocomplete_result.h b/components/omnibox/browser/autocomplete_result.h
index 88619705..06dfd23a 100644
--- a/components/omnibox/browser/autocomplete_result.h
+++ b/components/omnibox/browser/autocomplete_result.h
@@ -161,6 +161,14 @@
       const ACMatches& old_matches,
       const ACMatches& new_matches);
 
+  // This pulls the relevant fields out of a match for comparison with other
+  // matches for the purpose of deduping. It uses the stripped URL, so that we
+  // collapse similar URLs if necessary, and whether the match is a calculator
+  // suggestion, because we don't want to dedupe them against URLs that simply
+  // happen to go to the same destination.
+  static std::pair<GURL, bool> GetMatchComparisonFields(
+      const AutocompleteMatch& match);
+
   ACMatches matches_;
 
   const_iterator default_match_;
diff --git a/components/omnibox/browser/base_search_provider.cc b/components/omnibox/browser/base_search_provider.cc
index 946cfbf..5129a431 100644
--- a/components/omnibox/browser/base_search_provider.cc
+++ b/components/omnibox/browser/base_search_provider.cc
@@ -292,13 +292,18 @@
         suggestion.suggestion().substr(input.text().length());
     match.allowed_to_be_default_match = true;
   }
-  match.fill_into_edit.append(suggestion.suggestion());
 
   const TemplateURLRef& search_url = template_url->url_ref();
   DCHECK(search_url.SupportsReplacement(search_terms_data));
-  match.search_terms_args.reset(
-      new TemplateURLRef::SearchTermsArgs(suggestion.suggestion()));
-  match.search_terms_args->original_query = input.text();
+  base::string16 query(suggestion.suggestion());
+  base::string16 original_query(input.text());
+  if (suggestion.type() == AutocompleteMatchType::CALCULATOR) {
+    query = original_query;
+    original_query.clear();
+  }
+  match.fill_into_edit.append(query);
+  match.search_terms_args.reset(new TemplateURLRef::SearchTermsArgs(query));
+  match.search_terms_args->original_query = original_query;
   match.search_terms_args->accepted_suggestion = accepted_suggestion;
   match.search_terms_args->additional_query_params =
       suggestion.additional_query_params();
diff --git a/components/omnibox/browser/match_compare.h b/components/omnibox/browser/match_compare.h
index 3a2b184..5bd8124 100644
--- a/components/omnibox/browser/match_compare.h
+++ b/components/omnibox/browser/match_compare.h
@@ -64,10 +64,4 @@
   CompareWithDemoteByType<Match> demote_by_type_;
 };
 
-struct MatchGURLHash {
-  size_t operator()(const GURL& gurl) const {
-    return std::hash<std::string>()(gurl.spec());
-  }
-};
-
 #endif  // COMPONENTS_OMNIBOX_BROWSER_MATCH_COMPARE_H_
diff --git a/components/omnibox/browser/omnibox_client.cc b/components/omnibox/browser/omnibox_client.cc
index 598d847..33521319 100644
--- a/components/omnibox/browser/omnibox_client.cc
+++ b/components/omnibox/browser/omnibox_client.cc
@@ -73,6 +73,10 @@
   return nullptr;
 }
 
+QueryInOmnibox* OmniboxClient::GetQueryInOmnibox() {
+  return nullptr;
+}
+
 gfx::Image OmniboxClient::GetIconIfExtensionMatch(
     const AutocompleteMatch& match) const {
   return gfx::Image();
diff --git a/components/omnibox/browser/omnibox_client.h b/components/omnibox/browser/omnibox_client.h
index ddc5a86..9de4a97f 100644
--- a/components/omnibox/browser/omnibox_client.h
+++ b/components/omnibox/browser/omnibox_client.h
@@ -14,6 +14,7 @@
 
 class AutocompleteResult;
 class GURL;
+class QueryInOmnibox;
 class SessionID;
 class TemplateURL;
 class TemplateURLService;
@@ -93,6 +94,7 @@
   virtual TemplateURLService* GetTemplateURLService();
   virtual const AutocompleteSchemeClassifier& GetSchemeClassifier() const = 0;
   virtual AutocompleteClassifier* GetAutocompleteClassifier();
+  virtual QueryInOmnibox* GetQueryInOmnibox();
 
   // Returns the icon corresponding to |match| if match is an extension match
   // and an empty icon otherwise.
diff --git a/components/omnibox/browser/omnibox_edit_model.h b/components/omnibox/browser/omnibox_edit_model.h
index 6808095..8027da1b 100644
--- a/components/omnibox/browser/omnibox_edit_model.h
+++ b/components/omnibox/browser/omnibox_edit_model.h
@@ -367,6 +367,8 @@
   // Name of the histogram tracking cut or copy omnibox commands.
   static const char kCutOrCopyAllTextHistogram[];
 
+  OmniboxView* view() { return view_; }
+
  private:
   friend class OmniboxControllerTest;
   FRIEND_TEST_ALL_PREFIXES(OmniboxEditModelTest, ConsumeCtrlKey);
diff --git a/components/omnibox/browser/omnibox_popup_model.cc b/components/omnibox/browser/omnibox_popup_model.cc
index a68ecda..a84ce9b 100644
--- a/components/omnibox/browser/omnibox_popup_model.cc
+++ b/components/omnibox/browser/omnibox_popup_model.cc
@@ -187,19 +187,28 @@
   DCHECK(!result().empty());
   DCHECK_NE(kNoMatch, selected_line_);
 
+  const AutocompleteResult& result = this->result();
+  if (result.empty())
+    return;
+
+  const AutocompleteMatch& match = result.match_at(selected_line_);
+  GURL current_destination(match.destination_url);
+
   if (state == KEYWORD) {
-    const AutocompleteMatch& match = result().match_at(selected_line_);
     DCHECK(match.associated_keyword.get());
   }
 
   if (state == TAB_SWITCH) {
-    const AutocompleteMatch& match = result().match_at(selected_line_);
     DCHECK(match.has_tab_match);
-    old_focused_url_ = result().match_at(selected_line_).destination_url;
+    old_focused_url_ = current_destination;
   }
 
   selected_line_state_ = state;
   view_->InvalidateLine(selected_line_);
+
+  // Ensures update of accessibility data.
+  edit_model_->view()->OnTemporaryTextMaybeChanged(
+    edit_model_->view()->GetText(), match, false, false);
 }
 
 void OmniboxPopupModel::TryDeletingCurrentItem() {
diff --git a/components/omnibox_strings.grdp b/components/omnibox_strings.grdp
index 8a052c8..e6fd35a 100644
--- a/components/omnibox_strings.grdp
+++ b/components/omnibox_strings.grdp
@@ -93,8 +93,15 @@
   <message name="IDS_ACC_AUTOCOMPLETE_N_OF_M" desc="Text for screenreaders describing the current matche's position in the list of suggestions.">
     <ph name="FRIENDLY_MATCH_TEXT">$1<ex>The Chromium Projects http://www.chromium.org bookmark</ex></ph>, <ph name="MATCH_POSITION">$2<ex>2</ex></ph> of <ph name="NUM_MATCHES">$3<ex>3</ex></ph>
   </message>
-  <!-- Accessibility suffix for suggestions with a tab switch match. Comma is important. -->
+  <!-- Accessibility suffix for suggestions with a tab switch match. Commas are important as they add pauses. -->
   <message name="IDS_ACC_TAB_SWITCH_SUFFIX" desc="Suffix for tab switch suggestions to explain keystroke used to switch.">
     <ph name="TAB_SWITCH_SUFFIX">$1, currently open, press tab then enter to switch to the open tab</ph>
   </message>
+  <!-- Accessibility prefix for suggestions where the tab switch button is focused. Commas are important as they add pauses. -->
+  <message name="IDS_ACC_TAB_SWITCH_BUTTON_FOCUSED_PREFIX" desc="Announcement when tab switch button focused.">
+    <ph name="TAB_SWITCH_FOCUSED_FRIENDLY_MATCH_TEXT">Tab switch button, press enter to switch to the open tab, $1<ex>The Chromium Projects http://www.chromium.org bookmark</ex></ph>
+  </message>
+  <message name="IDS_ACC_TAB_SWITCH_BUTTON" desc="Announcement when tab switch button focused.">
+    Tab switch button, press enter to switch to this tab
+  </message>
 </grit-part>
diff --git a/components/password_manager/core/browser/new_password_form_manager.cc b/components/password_manager/core/browser/new_password_form_manager.cc
index 886263fa..86e21b6 100644
--- a/components/password_manager/core/browser/new_password_form_manager.cc
+++ b/components/password_manager/core/browser/new_password_form_manager.cc
@@ -267,12 +267,31 @@
 void NewPasswordFormManager::Update(const PasswordForm& credentials_to_update) {
 }
 
+void NewPasswordFormManager::UpdateUsername(
+    const base::string16& new_username) {
+  DCHECK(parsed_submitted_form_);
+  parsed_submitted_form_->username_value = new_username;
+  parsed_submitted_form_->username_element.clear();
+
+  // TODO(https://crbug.com/831123): Implement processing username editing votes
+  // after implementation of |other_possible_usernames|.
+
+  CreatePendingCredentials();
+}
+
+void NewPasswordFormManager::UpdatePasswordValue(
+    const base::string16& new_password) {
+  DCHECK(parsed_submitted_form_);
+  parsed_submitted_form_->password_value = new_password;
+  parsed_submitted_form_->password_element.clear();
+
+  // TODO(https://crbug.com/831123): Implement processing password editing votes
+  // after implementation of |all_possible_passwords|.
+  CreatePendingCredentials();
+}
+
 // TODO(https://crbug.com/831123): Implement all methods from
 // PasswordFormManagerForUI.
-void NewPasswordFormManager::UpdateUsername(
-    const base::string16& new_username) {}
-void NewPasswordFormManager::UpdatePasswordValue(
-    const base::string16& new_password) {}
 void NewPasswordFormManager::OnNopeUpdateClicked() {}
 void NewPasswordFormManager::OnNeverClicked() {}
 void NewPasswordFormManager::OnNoInteraction(bool is_update) {}
@@ -343,6 +362,8 @@
     return false;
   submitted_form_ = submitted_form;
   is_submitted_ = true;
+  parsed_submitted_form_ = ParseFormAndMakeLogging(
+      client_, submitted_form_, predictions_, FormParsingMode::SAVING);
   CreatePendingCredentials();
   return true;
 }
@@ -440,8 +461,6 @@
   DCHECK(is_submitted_);
   // TODO(https://crbug.com/831123): Process correctly the case when saved
   // credentials are not received from the store yet.
-  parsed_submitted_form_ = ParseFormAndMakeLogging(
-      client_, submitted_form_, predictions_, FormParsingMode::SAVING);
   if (!parsed_submitted_form_)
     return;
 
diff --git a/components/password_manager/core/browser/new_password_form_manager_unittest.cc b/components/password_manager/core/browser/new_password_form_manager_unittest.cc
index a59ca7a..bd73fe3e 100644
--- a/components/password_manager/core/browser/new_password_form_manager_unittest.cc
+++ b/components/password_manager/core/browser/new_password_form_manager_unittest.cc
@@ -149,6 +149,10 @@
     field.unique_renderer_id = 5;
     observed_form_only_password_fields_.fields.push_back(field);
 
+    submitted_form_ = observed_form_;
+    submitted_form_.fields[kUsernameFieldIndex].value = ASCIIToUTF16("user1");
+    submitted_form_.fields[kPasswordFieldIndex].value = ASCIIToUTF16("secret1");
+
     saved_match_.origin = origin;
     saved_match_.action = action;
     saved_match_.signon_realm = "https://accounts.google.com/";
@@ -166,10 +170,18 @@
     psl_saved_match_.signon_realm = "https://myaccounts.google.com/";
     psl_saved_match_.is_public_suffix_match = true;
 
-    parsed_form_ = saved_match_;
-    parsed_form_.form_data = observed_form_;
-    parsed_form_.username_element = observed_form_.fields[1].name;
-    parsed_form_.password_element = observed_form_.fields[2].name;
+    parsed_observed_form_ = saved_match_;
+    parsed_observed_form_.form_data = observed_form_;
+    parsed_observed_form_.username_element =
+        observed_form_.fields[kUsernameFieldIndex].name;
+    parsed_observed_form_.password_element =
+        observed_form_.fields[kPasswordFieldIndex].name;
+
+    parsed_submitted_form_ = parsed_observed_form_;
+    parsed_submitted_form_.username_value =
+        submitted_form_.fields[kUsernameFieldIndex].value;
+    parsed_submitted_form_.password_value =
+        submitted_form_.fields[kPasswordFieldIndex].value;
 
     blacklisted_match_ = saved_match_;
     blacklisted_match_.blacklisted_by_user = true;
@@ -179,11 +191,13 @@
 
  protected:
   FormData observed_form_;
+  FormData submitted_form_;
   FormData observed_form_only_password_fields_;
   PasswordForm saved_match_;
   PasswordForm psl_saved_match_;
   PasswordForm blacklisted_match_;
-  PasswordForm parsed_form_;
+  PasswordForm parsed_observed_form_;
+  PasswordForm parsed_submitted_form_;
   StubPasswordManagerClient client_;
   MockPasswordManagerDriver driver_;
   scoped_refptr<TestMockTimeTaskRunner> task_runner_;
@@ -398,17 +412,10 @@
   TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
   fetcher_->SetNonFederated({}, 0u);
 
-  FormData submitted_form = observed_form_;
-  submitted_form.fields[kUsernameFieldIndex].value = ASCIIToUTF16("user1");
-  submitted_form.fields[kPasswordFieldIndex].value = ASCIIToUTF16("pw1");
-
-  PasswordForm expected = parsed_form_;
-  expected.username_value = ASCIIToUTF16("user1");
-  expected.password_value = ASCIIToUTF16("pw1");
-
   EXPECT_TRUE(
-      form_manager_->SetSubmittedFormIfIsManaged(submitted_form, &driver_));
-  CheckPendingCredentials(expected, form_manager_->GetPendingCredentials());
+      form_manager_->SetSubmittedFormIfIsManaged(submitted_form_, &driver_));
+  CheckPendingCredentials(parsed_submitted_form_,
+                          form_manager_->GetPendingCredentials());
 }
 
 // Tests creating pending credentials when new credentials are submitted and the
@@ -417,18 +424,10 @@
   TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
   fetcher_->SetNonFederated({&saved_match_}, 0u);
 
-  FormData submitted_form = observed_form_;
-  base::string16 username = saved_match_.username_value + ASCIIToUTF16("1");
-  base::string16 password = saved_match_.password_value + ASCIIToUTF16("1");
-  submitted_form.fields[kUsernameFieldIndex].value = username;
-  submitted_form.fields[kPasswordFieldIndex].value = password;
-  PasswordForm expected = parsed_form_;
-  expected.username_value = username;
-  expected.password_value = password;
-
   EXPECT_TRUE(
-      form_manager_->SetSubmittedFormIfIsManaged(submitted_form, &driver_));
-  CheckPendingCredentials(expected, form_manager_->GetPendingCredentials());
+      form_manager_->SetSubmittedFormIfIsManaged(submitted_form_, &driver_));
+  CheckPendingCredentials(parsed_submitted_form_,
+                          form_manager_->GetPendingCredentials());
 }
 
 // Tests that when submitted credentials are equal to already saved one then
@@ -437,13 +436,12 @@
   TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
   fetcher_->SetNonFederated({&saved_match_}, 0u);
 
-  FormData submitted_form = observed_form_;
-  submitted_form.fields[kUsernameFieldIndex].value =
+  submitted_form_.fields[kUsernameFieldIndex].value =
       saved_match_.username_value;
-  submitted_form.fields[kPasswordFieldIndex].value =
+  submitted_form_.fields[kPasswordFieldIndex].value =
       saved_match_.password_value;
   EXPECT_TRUE(
-      form_manager_->SetSubmittedFormIfIsManaged(submitted_form, &driver_));
+      form_manager_->SetSubmittedFormIfIsManaged(submitted_form_, &driver_));
   CheckPendingCredentials(/* expected */ saved_match_,
                           form_manager_->GetPendingCredentials());
 }
@@ -460,14 +458,13 @@
 
   fetcher_->SetNonFederated({&saved_match_}, 0u);
 
-  FormData submitted_form = observed_form_;
-  submitted_form.fields[kUsernameFieldIndex].value =
+  submitted_form_.fields[kUsernameFieldIndex].value =
       saved_match_.username_value;
-  submitted_form.fields[kPasswordFieldIndex].value =
+  submitted_form_.fields[kPasswordFieldIndex].value =
       saved_match_.password_value;
 
   EXPECT_TRUE(
-      form_manager_->SetSubmittedFormIfIsManaged(submitted_form, &driver_));
+      form_manager_->SetSubmittedFormIfIsManaged(submitted_form_, &driver_));
   CheckPendingCredentials(expected, form_manager_->GetPendingCredentials());
 }
 
@@ -480,12 +477,11 @@
   PasswordForm expected = saved_match_;
   expected.password_value += ASCIIToUTF16("1");
 
-  FormData submitted_form = observed_form_;
-  submitted_form.fields[kUsernameFieldIndex].value =
+  submitted_form_.fields[kUsernameFieldIndex].value =
       saved_match_.username_value;
-  submitted_form.fields[kPasswordFieldIndex].value = expected.password_value;
+  submitted_form_.fields[kPasswordFieldIndex].value = expected.password_value;
   EXPECT_TRUE(
-      form_manager_->SetSubmittedFormIfIsManaged(submitted_form, &driver_));
+      form_manager_->SetSubmittedFormIfIsManaged(submitted_form_, &driver_));
   CheckPendingCredentials(expected, form_manager_->GetPendingCredentials());
 }
 
@@ -743,4 +739,76 @@
   EXPECT_EQ(not_best_saved_match, credentials_to_update[0]);
 }
 
+TEST_F(NewPasswordFormManagerTest, UpdateUsernameEmptyStore) {
+  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
+  fetcher_->SetNonFederated({}, 0u);
+
+  form_manager_->SetSubmittedFormIfIsManaged(submitted_form_, &driver_);
+
+  base::string16 new_username =
+      parsed_submitted_form_.username_value + ASCIIToUTF16("1");
+  PasswordForm expected = parsed_submitted_form_;
+  expected.username_value = new_username;
+  expected.username_element.clear();
+
+  form_manager_->UpdateUsername(new_username);
+
+  CheckPendingCredentials(expected, form_manager_->GetPendingCredentials());
+  EXPECT_TRUE(form_manager_->IsNewLogin());
+}
+
+TEST_F(NewPasswordFormManagerTest, UpdateUsernameToAlreadyExisting) {
+  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
+  fetcher_->SetNonFederated({&saved_match_}, 0u);
+
+  form_manager_->SetSubmittedFormIfIsManaged(submitted_form_, &driver_);
+
+  base::string16 new_username = saved_match_.username_value;
+  base::string16 expected_password = parsed_submitted_form_.password_value;
+  PasswordForm expected = saved_match_;
+  expected.password_value = expected_password;
+
+  form_manager_->UpdateUsername(new_username);
+
+  CheckPendingCredentials(expected, form_manager_->GetPendingCredentials());
+  EXPECT_FALSE(form_manager_->IsNewLogin());
+  EXPECT_TRUE(form_manager_->IsPasswordOverridden());
+}
+
+TEST_F(NewPasswordFormManagerTest, UpdatePasswordEmptyStore) {
+  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
+  fetcher_->SetNonFederated({}, 0u);
+
+  form_manager_->SetSubmittedFormIfIsManaged(submitted_form_, &driver_);
+
+  base::string16 new_password =
+      parsed_submitted_form_.password_value + ASCIIToUTF16("1");
+  PasswordForm expected = parsed_submitted_form_;
+  expected.password_value = new_password;
+  expected.password_element.clear();
+
+  form_manager_->UpdatePasswordValue(new_password);
+
+  CheckPendingCredentials(expected, form_manager_->GetPendingCredentials());
+  EXPECT_TRUE(form_manager_->IsNewLogin());
+}
+
+TEST_F(NewPasswordFormManagerTest, UpdatePasswordToAlreadyExisting) {
+  TestMockTimeTaskRunner::ScopedContext scoped_context(task_runner_.get());
+  fetcher_->SetNonFederated({&saved_match_}, 0u);
+
+  // Emulate submitting form with known username and different password.
+  submitted_form_.fields[kUsernameFieldIndex].value =
+      saved_match_.username_value;
+  form_manager_->SetSubmittedFormIfIsManaged(submitted_form_, &driver_);
+
+  // The user changes password to already saved one.
+  base::string16 password = saved_match_.password_value;
+  form_manager_->UpdatePasswordValue(password);
+
+  CheckPendingCredentials(saved_match_, form_manager_->GetPendingCredentials());
+  EXPECT_FALSE(form_manager_->IsNewLogin());
+  EXPECT_FALSE(form_manager_->IsPasswordOverridden());
+}
+
 }  // namespace  password_manager
diff --git a/components/password_manager/core/browser/password_manager.cc b/components/password_manager/core/browser/password_manager.cc
index dc0b8a5..7b69e4a 100644
--- a/components/password_manager/core/browser/password_manager.cc
+++ b/components/password_manager/core/browser/password_manager.cc
@@ -1169,10 +1169,16 @@
   if (owned_submitted_form_manager_)
     return std::move(owned_submitted_form_manager_);
 
-  for (std::unique_ptr<NewPasswordFormManager>& manager : form_managers_) {
-    if (manager->is_submitted())
-      return std::move(manager);
+  for (auto iter = form_managers_.begin(); iter != form_managers_.end();
+       ++iter) {
+    if ((*iter)->is_submitted()) {
+      std::unique_ptr<NewPasswordFormManager> submitted_manager =
+          std::move(*iter);
+      form_managers_.erase(iter);
+      return std::move(submitted_manager);
+    }
   }
+
   NOTREACHED();
   return nullptr;
 }
diff --git a/components/password_manager/core/browser/password_manager_unittest.cc b/components/password_manager/core/browser/password_manager_unittest.cc
index 5461e34..4b99776 100644
--- a/components/password_manager/core/browser/password_manager_unittest.cc
+++ b/components/password_manager/core/browser/password_manager_unittest.cc
@@ -2625,6 +2625,7 @@
   EXPECT_CALL(client_, PromptUserToSaveOrUpdatePasswordPtr(_))
       .WillOnce(WithArg<0>(SaveToScopedPtr(&form_manager_to_save)));
   manager()->OnPasswordFormSubmittedNoChecks(&driver_, submitted_form);
+  EXPECT_TRUE(manager()->form_managers().empty());
 }
 
 TEST_F(PasswordManagerTest, SubmittedGaiaFormWithoutVisiblePasswordField) {
diff --git a/components/password_manager/core/common/password_manager_features.cc b/components/password_manager/core/common/password_manager_features.cc
index b41d1f61..efbfb6d 100644
--- a/components/password_manager/core/common/password_manager_features.cc
+++ b/components/password_manager/core/common/password_manager_features.cc
@@ -51,10 +51,6 @@
 const base::Feature kProtectSyncCredentialOnReauth = {
     "ProtectSyncCredentialOnReauth", base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Controls the ability to export passwords from Chrome's settings page.
-const base::Feature kPasswordExport = {"PasswordExport",
-                                       base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Controls the ability to import passwords from Chrome's settings page.
 const base::Feature kPasswordImport = {"PasswordImport",
                                        base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/components/password_manager/core/common/password_manager_features.h b/components/password_manager/core/common/password_manager_features.h
index 160f424..b163416 100644
--- a/components/password_manager/core/common/password_manager_features.h
+++ b/components/password_manager/core/common/password_manager_features.h
@@ -28,7 +28,6 @@
 extern const base::Feature kMigrateLinuxToLoginDB;
 extern const base::Feature kNewPasswordFormParsing;
 extern const base::Feature kNewPasswordFormParsingForSaving;
-extern const base::Feature kPasswordExport;
 extern const base::Feature kPasswordImport;
 extern const base::Feature kPasswordSearchMobile;
 extern const base::Feature kPasswordsKeyboardAccessory;
diff --git a/components/password_manager/sync/browser/password_sync_util_unittest.cc b/components/password_manager/sync/browser/password_sync_util_unittest.cc
index c65e51b..92e92e3d 100644
--- a/components/password_manager/sync/browser/password_sync_util_unittest.cc
+++ b/components/password_manager/sync/browser/password_sync_util_unittest.cc
@@ -16,9 +16,7 @@
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if !defined(OS_IOS)
-#include "base/test/scoped_feature_list.h"
 #include "components/safe_browsing/common/safe_browsing_prefs.h"
-#include "components/safe_browsing/features.h"
 #endif  // !OS_IOS
 
 using autofill::PasswordForm;
@@ -133,13 +131,10 @@
     prefs_.registry()->RegisterListPref(prefs::kPasswordProtectionLoginURLs);
     prefs_.registry()->RegisterStringPref(
         prefs::kPasswordProtectionChangePasswordURL, "");
-    feature_list_.InitAndEnableFeature(
-        safe_browsing::kEnterprisePasswordProtectionV1);
   }
 
  protected:
   TestingPrefServiceSimple prefs_;
-  base::test::ScopedFeatureList feature_list_;
 };
 
 TEST_F(PasswordSyncUtilEnterpriseTest, ShouldSavePasswordHash) {
diff --git a/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc b/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc
index b28a3fd68..698ed6f 100644
--- a/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc
+++ b/components/password_manager/sync/browser/sync_credentials_filter_unittest.cc
@@ -429,9 +429,6 @@
   PasswordForm other_form = SimpleNonGaiaForm("user@example.org");
   EXPECT_FALSE(filter_.ShouldSaveEnterprisePasswordHash(other_form));
 
-  base::test::ScopedFeatureList scoped_feature_list;
-  scoped_feature_list.InitAndEnableFeature(
-      safe_browsing::kEnterprisePasswordProtectionV1);
   PasswordForm enterprise_form =
       SimpleNonGaiaForm("user@enterprise.test", kEnterpriseURL);
   EXPECT_TRUE(filter_.ShouldSaveEnterprisePasswordHash(enterprise_form));
diff --git a/components/previews/core/BUILD.gn b/components/previews/core/BUILD.gn
index 71b38221..7001c42 100644
--- a/components/previews/core/BUILD.gn
+++ b/components/previews/core/BUILD.gn
@@ -4,6 +4,8 @@
 
 static_library("core") {
   sources = [
+    "bloom_filter.cc",
+    "bloom_filter.h",
     "previews_black_list.cc",
     "previews_black_list.h",
     "previews_decider.h",
@@ -26,6 +28,7 @@
     "//components/variations",
     "//net:net",
     "//third_party/re2",
+    "//third_party/smhasher:murmurhash3",
     "//url:url",
   ]
 }
@@ -51,6 +54,7 @@
 source_set("unit_tests") {
   testonly = true
   sources = [
+    "bloom_filter_unittest.cc",
     "previews_black_list_unittest.cc",
     "previews_experiments_unittest.cc",
     "previews_logger_unittest.cc",
diff --git a/components/previews/core/DEPS b/components/previews/core/DEPS
index 11d53fd..776d207 100644
--- a/components/previews/core/DEPS
+++ b/components/previews/core/DEPS
@@ -2,5 +2,6 @@
   "+components/blacklist/opt_out_blacklist",
   "+components/variations",
   "+net",
-  "+third_party/re2"
+  "+third_party/re2",
+  "+third_party/smhasher"
 ]
diff --git a/components/previews/core/bloom_filter.cc b/components/previews/core/bloom_filter.cc
new file mode 100644
index 0000000..7fba11c7
--- /dev/null
+++ b/components/previews/core/bloom_filter.cc
@@ -0,0 +1,62 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/previews/core/bloom_filter.h"
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "base/logging.h"
+#include "third_party/smhasher/src/MurmurHash3.h"
+
+namespace previews {
+
+namespace {
+
+uint64_t MurmurHash3(const std::string& str, uint32_t seed) {
+  // Uses MurmurHash3 in coordination with server as it is a fast hashing
+  // function with compatible public client and private server implementations.
+  // DO NOT CHANGE this hashing function without coordination and migration
+  // plan with the server.
+  uint64_t output[2];
+  MurmurHash3_x64_128(str.data(), str.size(), seed, &output);
+  // Drop the last 64 bits.
+  return output[0];
+}
+
+}  // namespace
+
+BloomFilter::BloomFilter(uint32_t num_bits,
+                         ByteVector filter_data,
+                         uint32_t num_hash_functions)
+
+    : num_bits_(num_bits),
+      bytes_(filter_data),
+      num_hash_functions_(num_hash_functions) {
+  CHECK_GE(filter_data.size() * 8, num_bits);
+}
+
+BloomFilter::~BloomFilter() {}
+
+bool BloomFilter::Contains(const std::string& str) const {
+  for (size_t i = 0; i < num_hash_functions_; ++i) {
+    uint64_t n = MurmurHash3(str, i) % num_bits_;
+    uint32_t byte_index = (n / 8);
+    uint32_t bit_index = n % 8;
+    if ((bytes_[byte_index] & (1 << bit_index)) == 0)
+      return false;
+  }
+  return true;
+}
+
+void BloomFilter::Add(const std::string& str) {
+  for (size_t i = 0; i < num_hash_functions_; ++i) {
+    uint64_t n = MurmurHash3(str, i) % num_bits_;
+    uint32_t byte_index = (n / 8);
+    uint32_t bit_index = n % 8;
+    bytes_[byte_index] |= 1 << bit_index;
+  }
+}
+
+}  // namespace previews
diff --git a/components/previews/core/bloom_filter.h b/components/previews/core/bloom_filter.h
new file mode 100644
index 0000000..eca513b
--- /dev/null
+++ b/components/previews/core/bloom_filter.h
@@ -0,0 +1,55 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_PREVIEWS_CORE_BLOOM_FILTER_H_
+#define COMPONENTS_PREVIEWS_CORE_BLOOM_FILTER_H_
+
+#include <stdint.h>
+
+#include <string>
+#include <vector>
+
+#include "base/macros.h"
+
+namespace previews {
+
+// A vector of bytes (or 8-bit integers).
+typedef std::vector<uint8_t> ByteVector;
+
+// BloomFilter is a simple Bloom filter for keeping track of a set of strings.
+class BloomFilter {
+ public:
+  // Constructs a Bloom filter of |num_bits| size with data initialized from
+  // the |filter_data| byte vector and using |num_hash_functions| per entry.
+  BloomFilter(uint32_t num_bits,
+              ByteVector filter_data,
+              uint32_t num_hash_functions);
+
+  ~BloomFilter();
+
+  // Returns whether this Bloom filter contains |str|.
+  bool Contains(const std::string& str) const;
+
+  // Adds |str| to this Bloom filter.
+  void Add(const std::string& str);
+
+  // Returns the bit array data of this Bloom filter as vector of bytes.
+  const ByteVector& bytes() const { return bytes_; };
+
+ private:
+  // Number of bits in the filter.
+  uint32_t num_bits_;
+
+  // Byte data for the filter.
+  ByteVector bytes_;
+
+  // Number of bits to set for each added string.
+  uint32_t num_hash_functions_;
+
+  DISALLOW_COPY_AND_ASSIGN(BloomFilter);
+};
+
+}  // namespace previews
+
+#endif  // COMPONENTS_PREVIEWS_CORE_BLOOM_FILTER_H_
diff --git a/components/previews/core/bloom_filter_unittest.cc b/components/previews/core/bloom_filter_unittest.cc
new file mode 100644
index 0000000..df1c8a82
--- /dev/null
+++ b/components/previews/core/bloom_filter_unittest.cc
@@ -0,0 +1,112 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/previews/core/bloom_filter.h"
+
+#include <stdint.h>
+
+#include "build/build_config.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace previews {
+
+namespace {
+
+int CountBits(const ByteVector& vector) {
+  int bit_count = 0;
+  for (size_t i = 0; i < vector.size(); ++i) {
+    uint8_t byte = vector[i];
+    for (int j = 0; j < 8; ++j) {
+      if (byte & (1 << j))
+        bit_count++;
+    }
+  }
+  return bit_count;
+}
+
+}  // namespace
+
+TEST(BloomFilterTest, SingleHash) {
+  ByteVector data(2, 0);
+  BloomFilter filter(16 /* num_bits */, data, 1 /* num_hash_functions */);
+  EXPECT_EQ(2u, filter.bytes().size());
+  EXPECT_EQ(0, CountBits(filter.bytes()));
+
+  EXPECT_FALSE(filter.Contains("Alfa"));
+  EXPECT_FALSE(filter.Contains("Bravo"));
+  EXPECT_FALSE(filter.Contains("Charlie"));
+
+  filter.Add("Alfa");
+  EXPECT_EQ(1, CountBits(filter.bytes()));
+  EXPECT_TRUE(filter.Contains("Alfa"));
+  EXPECT_FALSE(filter.Contains("Bravo"));
+  EXPECT_FALSE(filter.Contains("Charlie"));
+
+  filter.Add("Bravo");
+  filter.Add("Chuck");
+  EXPECT_EQ(3, CountBits(filter.bytes()));
+  EXPECT_TRUE(filter.Contains("Alfa"));
+  EXPECT_TRUE(filter.Contains("Bravo"));
+  EXPECT_FALSE(filter.Contains("Charlie"));
+}
+
+TEST(BloomFilterTest, FalsePositivesWithSingleBitFilterCollisions) {
+  ByteVector data(1, 0);
+  BloomFilter filter(1 /* num_bits */, data, 1 /* num_hash_functions */);
+
+  EXPECT_FALSE(filter.Contains("Alfa"));
+  EXPECT_FALSE(filter.Contains("Bravo"));
+  EXPECT_FALSE(filter.Contains("Charlie"));
+
+  filter.Add("Alfa");
+  EXPECT_TRUE(filter.Contains("Alfa"));
+  EXPECT_TRUE(filter.Contains("Bravo"));
+  EXPECT_TRUE(filter.Contains("Charlie"));
+}
+
+TEST(BloomFilterTest, MultiHash) {
+  ByteVector data(10, 0);
+  BloomFilter filter(75 /* num_bits */, data, 3 /* num_hash_functions */);
+  EXPECT_EQ(10u, filter.bytes().size());
+  EXPECT_EQ(0, CountBits(filter.bytes()));
+
+  EXPECT_FALSE(filter.Contains("Alfa"));
+  EXPECT_FALSE(filter.Contains("Bravo"));
+  EXPECT_FALSE(filter.Contains("Charlie"));
+
+  filter.Add("Alfa");
+  EXPECT_EQ(3, CountBits(filter.bytes()));
+  EXPECT_TRUE(filter.Contains("Alfa"));
+  EXPECT_FALSE(filter.Contains("Bravo"));
+  EXPECT_FALSE(filter.Contains("Charlie"));
+
+  filter.Add("Bravo");
+  filter.Add("Chuck");
+  EXPECT_EQ(9, CountBits(filter.bytes()));
+  EXPECT_TRUE(filter.Contains("Alfa"));
+  EXPECT_TRUE(filter.Contains("Bravo"));
+  EXPECT_FALSE(filter.Contains("Charlie"));
+}
+
+TEST(BloomFilterTest, EverythingMatches) {
+  // Set all bits ON in byte vector.
+  ByteVector data(1024, 0xff);
+  BloomFilter filter(8191 /* num_bits */, data, 7 /* num_hash_functions */);
+
+  EXPECT_TRUE(filter.Contains("Alfa"));
+  EXPECT_TRUE(filter.Contains("Bravo"));
+  EXPECT_TRUE(filter.Contains("Charlie"));
+  EXPECT_TRUE(filter.Contains("Delta"));
+  EXPECT_TRUE(filter.Contains("Echo"));
+}
+
+#if !defined(OS_IOS)
+TEST(BloomFilterTest, ByteVectorTooSmall) {
+  ByteVector data(1023, 0xff);
+  EXPECT_DEATH({ BloomFilter filter(8191 /* num_bits */, data, 7); },
+               "Check failed");
+}
+#endif
+
+}  // namespace previews
diff --git a/components/printing/common/printer_capabilities.cc b/components/printing/common/printer_capabilities.cc
index 902da5e..d8fc0d4 100644
--- a/components/printing/common/printer_capabilities.cc
+++ b/components/printing/common/printer_capabilities.cc
@@ -12,7 +12,7 @@
 #include "base/logging.h"
 #include "base/stl_util.h"
 #include "base/strings/string_piece.h"
-#include "base/threading/thread_restrictions.h"
+#include "base/threading/scoped_blocking_call.h"
 #include "base/values.h"
 #include "build/build_config.h"
 #include "components/crash/core/common/crash_keys.h"
@@ -40,7 +40,7 @@
 GetPrinterCapabilitiesOnBlockingPoolThread(
     const std::string& device_name,
     scoped_refptr<PrintBackend> print_backend) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
   DCHECK(!device_name.empty());
   scoped_refptr<PrintBackend> backend =
       print_backend ? print_backend
@@ -113,7 +113,7 @@
     const std::string& device_name,
     const PrinterBasicInfo& basic_info,
     scoped_refptr<PrintBackend> print_backend) {
-  base::AssertBlockingAllowed();
+  base::ScopedBlockingCall scoped_blocking_call(base::BlockingType::MAY_BLOCK);
 
   const auto printer_name_description =
       GetPrinterNameAndDescription(basic_info);
diff --git a/components/safe_browsing/common/safe_browsing_prefs.cc b/components/safe_browsing/common/safe_browsing_prefs.cc
index dd18f46..74a5a4e0 100644
--- a/components/safe_browsing/common/safe_browsing_prefs.cc
+++ b/components/safe_browsing/common/safe_browsing_prefs.cc
@@ -421,11 +421,9 @@
 void GetSafeBrowsingWhitelistDomainsPref(
     const PrefService& prefs,
     std::vector<std::string>* out_canonicalized_domain_list) {
-  if (base::FeatureList::IsEnabled(kEnterprisePasswordProtectionV1)) {
-    const base::ListValue* pref_value =
-        prefs.GetList(prefs::kSafeBrowsingWhitelistDomains);
-    CanonicalizeDomainList(*pref_value, out_canonicalized_domain_list);
-  }
+  const base::ListValue* pref_value =
+      prefs.GetList(prefs::kSafeBrowsingWhitelistDomains);
+  CanonicalizeDomainList(*pref_value, out_canonicalized_domain_list);
 }
 
 void CanonicalizeDomainList(
@@ -484,10 +482,8 @@
 
 bool MatchesPasswordProtectionLoginURL(const GURL& url,
                                        const PrefService& prefs) {
-  if (!base::FeatureList::IsEnabled(kEnterprisePasswordProtectionV1) ||
-      !url.is_valid()) {
+  if (!url.is_valid())
     return false;
-  }
 
   std::vector<GURL> login_urls;
   GetPasswordProtectionLoginURLsPref(prefs, &login_urls);
@@ -522,10 +518,8 @@
 
 bool MatchesPasswordProtectionChangePasswordURL(const GURL& url,
                                                 const PrefService& prefs) {
-  if (!base::FeatureList::IsEnabled(kEnterprisePasswordProtectionV1) ||
-      !url.is_valid()) {
+  if (!url.is_valid())
     return false;
-  }
 
   GURL change_password_url = GetPasswordProtectionChangePasswordURLPref(prefs);
   if (change_password_url.is_empty())
diff --git a/components/safe_browsing/common/safe_browsing_prefs_unittest.cc b/components/safe_browsing/common/safe_browsing_prefs_unittest.cc
index cf0367e..f9f13131 100644
--- a/components/safe_browsing/common/safe_browsing_prefs_unittest.cc
+++ b/components/safe_browsing/common/safe_browsing_prefs_unittest.cc
@@ -60,11 +60,6 @@
         base::JoinString(disabled_features, ","));
   }
 
-  void EnableEnterprisePasswordProtectionFeature() {
-    feature_list_.reset(new base::test::ScopedFeatureList);
-    feature_list_->InitAndEnableFeature(kEnterprisePasswordProtectionV1);
-  }
-
   std::string GetActivePref() { return GetExtendedReportingPrefName(prefs_); }
 
   // Convenience method for explicitly setting up all combinations of prefs and
@@ -187,8 +182,6 @@
 }
 
 TEST_F(SafeBrowsingPrefsTest, VerifyMatchesPasswordProtectionLoginURL) {
-  EnableEnterprisePasswordProtectionFeature();
-
   GURL url("https://mydomain.com/login.html#ref?username=alice");
   EXPECT_FALSE(prefs_.HasPrefPath(prefs::kPasswordProtectionLoginURLs));
   EXPECT_FALSE(MatchesPasswordProtectionLoginURL(url, prefs_));
@@ -207,8 +200,6 @@
 
 TEST_F(SafeBrowsingPrefsTest,
        VerifyMatchesPasswordProtectionChangePasswordURL) {
-  EnableEnterprisePasswordProtectionFeature();
-
   GURL url("https://mydomain.com/change_password.html#ref?username=alice");
   EXPECT_FALSE(prefs_.HasPrefPath(prefs::kPasswordProtectionChangePasswordURL));
   EXPECT_FALSE(MatchesPasswordProtectionChangePasswordURL(url, prefs_));
diff --git a/components/safe_browsing/features.cc b/components/safe_browsing/features.cc
index 8e8dd1c..878f4a6e 100644
--- a/components/safe_browsing/features.cc
+++ b/components/safe_browsing/features.cc
@@ -39,9 +39,6 @@
     "S13nSafeBrowsingCheckByURLLoaderThrottle",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
-const base::Feature kEnterprisePasswordProtectionV1{
-    "EnterprisePasswordProtectionV1", base::FEATURE_ENABLED_BY_DEFAULT};
-
 const base::Feature kForceEnableResetPasswordWebUI{
     "ForceEnableResetPasswordWebUI", base::FEATURE_DISABLED_BY_DEFAULT};
 
diff --git a/components/safe_browsing/features.h b/components/safe_browsing/features.h
index 6ff22ad..5d7dead 100644
--- a/components/safe_browsing/features.h
+++ b/components/safe_browsing/features.h
@@ -29,9 +29,6 @@
 
 extern const base::Feature kCheckByURLLoaderThrottle;
 
-// Controls the Password Protection for Enterprise V1 feature;
-extern const base::Feature kEnterprisePasswordProtectionV1;
-
 // Forces the chrome://reset-password page to be shown for review or testing
 // purpose.
 extern const base::Feature kForceEnableResetPasswordWebUI;
diff --git a/components/safe_browsing/password_protection/password_protection_service.cc b/components/safe_browsing/password_protection/password_protection_service.cc
index 7839c04..4a16b7e 100644
--- a/components/safe_browsing/password_protection/password_protection_service.cc
+++ b/components/safe_browsing/password_protection/password_protection_service.cc
@@ -22,7 +22,6 @@
 #include "components/safe_browsing/common/utils.h"
 #include "components/safe_browsing/db/database_manager.h"
 #include "components/safe_browsing/db/whitelist_checker_client.h"
-#include "components/safe_browsing/features.h"
 #include "components/safe_browsing/password_protection/password_protection_navigation_throttle.h"
 #include "components/safe_browsing/password_protection/password_protection_request.h"
 #include "content/public/browser/browser_thread.h"
@@ -836,7 +835,7 @@
     case PasswordReuseEvent::OTHER_GAIA_PASSWORD:
       return false;
     case PasswordReuseEvent::ENTERPRISE_PASSWORD:
-      return base::FeatureList::IsEnabled(kEnterprisePasswordProtectionV1);
+      return true;
     case PasswordReuseEvent::REUSED_PASSWORD_TYPE_UNKNOWN:
       break;
   }
diff --git a/components/safe_browsing/password_protection/password_protection_service_unittest.cc b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
index 448228d..102663e 100644
--- a/components/safe_browsing/password_protection/password_protection_service_unittest.cc
+++ b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
@@ -10,11 +10,9 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/null_task_runner.h"
-#include "base/test/scoped_feature_list.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/password_manager/core/browser/password_reuse_detector.h"
 #include "components/safe_browsing/db/test_database_manager.h"
-#include "components/safe_browsing/features.h"
 #include "components/safe_browsing/password_protection/metrics_util.h"
 #include "components/safe_browsing/password_protection/mock_password_protection_service.h"
 #include "components/safe_browsing/password_protection/password_protection_request.h"
@@ -1208,65 +1206,27 @@
 }
 
 TEST_P(PasswordProtectionServiceTest, VerifyIsSupportedPasswordTypeForPinging) {
-  {
-    base::test::ScopedFeatureList scoped_features;
-    scoped_features.InitAndDisableFeature(kEnterprisePasswordProtectionV1);
-    EXPECT_CALL(*password_protection_service_, GetSyncAccountType())
-        .WillRepeatedly(Return(PasswordReuseEvent::NOT_SIGNED_IN));
-    EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
-        PasswordReuseEvent::SAVED_PASSWORD));
-    EXPECT_FALSE(
-        password_protection_service_->IsSupportedPasswordTypeForPinging(
-            PasswordReuseEvent::SIGN_IN_PASSWORD));
-    EXPECT_FALSE(
-        password_protection_service_->IsSupportedPasswordTypeForPinging(
-            PasswordReuseEvent::OTHER_GAIA_PASSWORD));
-    EXPECT_FALSE(
-        password_protection_service_->IsSupportedPasswordTypeForPinging(
-            PasswordReuseEvent::ENTERPRISE_PASSWORD));
+  EXPECT_CALL(*password_protection_service_, GetSyncAccountType())
+      .WillRepeatedly(Return(PasswordReuseEvent::NOT_SIGNED_IN));
+  EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
+      PasswordReuseEvent::SAVED_PASSWORD));
+  EXPECT_FALSE(password_protection_service_->IsSupportedPasswordTypeForPinging(
+      PasswordReuseEvent::SIGN_IN_PASSWORD));
+  EXPECT_FALSE(password_protection_service_->IsSupportedPasswordTypeForPinging(
+      PasswordReuseEvent::OTHER_GAIA_PASSWORD));
+  EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
+      PasswordReuseEvent::ENTERPRISE_PASSWORD));
 
-    EXPECT_CALL(*password_protection_service_, GetSyncAccountType())
-        .WillRepeatedly(Return(PasswordReuseEvent::GMAIL));
-    EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
-        PasswordReuseEvent::SAVED_PASSWORD));
-    EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
-        PasswordReuseEvent::SIGN_IN_PASSWORD));
-    EXPECT_FALSE(
-        password_protection_service_->IsSupportedPasswordTypeForPinging(
-            PasswordReuseEvent::OTHER_GAIA_PASSWORD));
-    EXPECT_FALSE(
-        password_protection_service_->IsSupportedPasswordTypeForPinging(
-            PasswordReuseEvent::ENTERPRISE_PASSWORD));
-  }
-
-  {
-    base::test::ScopedFeatureList scoped_features;
-    scoped_features.InitAndEnableFeature(kEnterprisePasswordProtectionV1);
-    EXPECT_CALL(*password_protection_service_, GetSyncAccountType())
-        .WillRepeatedly(Return(PasswordReuseEvent::NOT_SIGNED_IN));
-    EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
-        PasswordReuseEvent::SAVED_PASSWORD));
-    EXPECT_FALSE(
-        password_protection_service_->IsSupportedPasswordTypeForPinging(
-            PasswordReuseEvent::SIGN_IN_PASSWORD));
-    EXPECT_FALSE(
-        password_protection_service_->IsSupportedPasswordTypeForPinging(
-            PasswordReuseEvent::OTHER_GAIA_PASSWORD));
-    EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
-        PasswordReuseEvent::ENTERPRISE_PASSWORD));
-
-    EXPECT_CALL(*password_protection_service_, GetSyncAccountType())
-        .WillRepeatedly(Return(PasswordReuseEvent::GMAIL));
-    EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
-        PasswordReuseEvent::SAVED_PASSWORD));
-    EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
-        PasswordReuseEvent::SIGN_IN_PASSWORD));
-    EXPECT_FALSE(
-        password_protection_service_->IsSupportedPasswordTypeForPinging(
-            PasswordReuseEvent::OTHER_GAIA_PASSWORD));
-    EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
-        PasswordReuseEvent::ENTERPRISE_PASSWORD));
-  }
+  EXPECT_CALL(*password_protection_service_, GetSyncAccountType())
+      .WillRepeatedly(Return(PasswordReuseEvent::GMAIL));
+  EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
+      PasswordReuseEvent::SAVED_PASSWORD));
+  EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
+      PasswordReuseEvent::SIGN_IN_PASSWORD));
+  EXPECT_FALSE(password_protection_service_->IsSupportedPasswordTypeForPinging(
+      PasswordReuseEvent::OTHER_GAIA_PASSWORD));
+  EXPECT_TRUE(password_protection_service_->IsSupportedPasswordTypeForPinging(
+      PasswordReuseEvent::ENTERPRISE_PASSWORD));
 }
 
 TEST_P(PasswordProtectionServiceTest, TestMigrateCachedVerdict) {
diff --git a/components/signin/core/browser/account_tracker_service.cc b/components/signin/core/browser/account_tracker_service.cc
index 26525d6..1704a91d 100644
--- a/components/signin/core/browser/account_tracker_service.cc
+++ b/components/signin/core/browser/account_tracker_service.cc
@@ -39,6 +39,12 @@
 const char kAdvancedProtectionAccountStatusPath[] =
     "is_under_advanced_protection";
 
+// Account folders used for storing account related data at disk.
+const base::FilePath::CharType kAccountsFolder[] =
+    FILE_PATH_LITERAL("Accounts");
+const base::FilePath::CharType kAvatarImagesFolder[] =
+    FILE_PATH_LITERAL("Avatar Images");
+
 // TODO(M48): Remove deprecated preference migration.
 const char kAccountServiceFlagsPath[] = "service_flags";
 
@@ -101,9 +107,6 @@
 // This must be a string which can never be a valid picture URL.
 const char AccountTrackerService::kNoPictureURLFound[] = "NO_PICTURE_URL";
 
-const char AccountTrackerService::kAccountsFolder[] = "Accounts";
-const char AccountTrackerService::kAvatarImagesFolder[] = "Avatar Images";
-
 AccountTrackerService::AccountTrackerService() : weak_factory_(this) {}
 
 AccountTrackerService::~AccountTrackerService() {
@@ -149,23 +152,17 @@
 
 std::vector<AccountInfo> AccountTrackerService::GetAccounts() const {
   std::vector<AccountInfo> accounts;
-
-  for (std::map<std::string, AccountState>::const_iterator it =
-           accounts_.begin();
-       it != accounts_.end();
-       ++it) {
-    const AccountState& state = it->second;
-    accounts.push_back(state.info);
+  for (const auto& pair : accounts_) {
+    accounts.push_back(pair.second.info);
   }
   return accounts;
 }
 
 AccountInfo AccountTrackerService::GetAccountInfo(
     const std::string& account_id) const {
-  std::map<std::string, AccountState>::const_iterator it =
-      accounts_.find(account_id);
-  if (it != accounts_.end())
-    return it->second.info;
+  const auto iterator = accounts_.find(account_id);
+  if (iterator != accounts_.end())
+    return iterator->second.info;
 
   return AccountInfo();
 }
@@ -173,14 +170,12 @@
 AccountInfo AccountTrackerService::FindAccountInfoByGaiaId(
     const std::string& gaia_id) const {
   if (!gaia_id.empty()) {
-    for (std::map<std::string, AccountState>::const_iterator it =
-             accounts_.begin();
-         it != accounts_.end();
-         ++it) {
-      const AccountState& state = it->second;
-      if (state.info.gaia == gaia_id)
-        return state.info;
-    }
+    const auto iterator = std::find_if(
+        accounts_.begin(), accounts_.end(), [&gaia_id](const auto& pair) {
+          return pair.second.info.gaia == gaia_id;
+        });
+    if (iterator != accounts_.end())
+      return iterator->second.info;
   }
 
   return AccountInfo();
@@ -189,14 +184,12 @@
 AccountInfo AccountTrackerService::FindAccountInfoByEmail(
     const std::string& email) const {
   if (!email.empty()) {
-    for (std::map<std::string, AccountState>::const_iterator it =
-             accounts_.begin();
-         it != accounts_.end();
-         ++it) {
-      const AccountState& state = it->second;
-      if (gaia::AreEmailsSame(state.info.email, email))
-        return state.info;
-    }
+    const auto iterator = std::find_if(
+        accounts_.begin(), accounts_.end(), [&email](const auto& pair) {
+          return gaia::AreEmailsSame(pair.second.info.email, email);
+        });
+    if (iterator != accounts_.end())
+      return iterator->second.info;
   }
 
   return AccountInfo();
@@ -204,8 +197,11 @@
 
 gfx::Image AccountTrackerService::GetAccountImage(
     const std::string& account_id) {
-  return base::ContainsKey(accounts_, account_id) ? accounts_[account_id].image
-                                                  : gfx::Image();
+  const auto iterator = accounts_.find(account_id);
+  if (iterator != accounts_.end())
+    return iterator->second.image;
+
+  return gfx::Image();
 }
 
 // static
@@ -300,7 +296,7 @@
     user_info->GetString("locale", &state.info.locale);
 
     std::string picture_url;
-    if(user_info->GetString("picture", &picture_url)) {
+    if (user_info->GetString("picture", &picture_url)) {
       state.info.picture_url = picture_url;
     } else {
       state.info.picture_url = kNoPictureURLFound;
@@ -435,8 +431,8 @@
 
 base::FilePath AccountTrackerService::GetImagePathFor(
     const std::string& account_id) {
-  return user_data_dir_.AppendASCII(kAccountsFolder)
-      .AppendASCII(kAvatarImagesFolder)
+  return user_data_dir_.Append(kAccountsFolder)
+      .Append(kAvatarImagesFolder)
       .AppendASCII(account_id);
 }
 
@@ -452,8 +448,8 @@
 void AccountTrackerService::LoadAccountImagesFromDisk() {
   if (!image_storage_task_runner_)
     return;
-  for (const std::pair<std::string, AccountState>& account : accounts_) {
-    const std::string& account_id = account.second.info.account_id;
+  for (const auto& pair : accounts_) {
+    const std::string& account_id = pair.second.info.account_id;
     PostTaskAndReplyWithResult(
         image_storage_task_runner_.get(), FROM_HERE,
         base::BindOnce(&ReadImage, GetImagePathFor(account_id)),
@@ -624,7 +620,7 @@
 
   base::string16 account_id_16 = base::UTF8ToUTF16(state.info.account_id);
   ListPrefUpdate update(pref_service_, kAccountInfoPref);
-  for(size_t i = 0; i < update->GetSize(); ++i) {
+  for (size_t i = 0; i < update->GetSize(); ++i) {
     base::DictionaryValue* dict = nullptr;
     if (update->GetDictionary(i, &dict)) {
       base::string16 value;
@@ -648,14 +644,15 @@
     const std::string& gaia,
     const std::string& email) {
   DCHECK(!gaia.empty() ||
-      GetMigrationState(pref_service) == MIGRATION_NOT_STARTED);
+         GetMigrationState(pref_service) == MIGRATION_NOT_STARTED);
   DCHECK(!email.empty());
-  switch(GetMigrationState(pref_service)) {
+  switch (GetMigrationState(pref_service)) {
     case MIGRATION_NOT_STARTED:
       // Some tests don't use a real email address.  To support these cases,
       // don't try to canonicalize these strings.
-      return (email.find('@') == std::string::npos) ? email :
-          gaia::CanonicalizeEmail(email);
+      return (email.find('@') == std::string::npos)
+                 ? email
+                 : gaia::CanonicalizeEmail(email);
     case MIGRATION_IN_PROGRESS:
     case MIGRATION_DONE:
       return gaia;
@@ -677,8 +674,7 @@
   SaveToPrefs(state);
 
   DVLOG(1) << "AccountTrackerService::SeedAccountInfo"
-           << " account_id=" << account_id
-           << " gaia_id=" << gaia
+           << " account_id=" << account_id << " gaia_id=" << gaia
            << " email=" << email;
 
   return account_id;
diff --git a/components/signin/core/browser/account_tracker_service.h b/components/signin/core/browser/account_tracker_service.h
index 901cf3a..caf6922 100644
--- a/components/signin/core/browser/account_tracker_service.h
+++ b/components/signin/core/browser/account_tracker_service.h
@@ -48,10 +48,6 @@
   // Child account service flag name.
   static const char kChildAccountServiceFlag[];
 
-  // Account folders used for storing account related data at disk.
-  static const char kAccountsFolder[];
-  static const char kAvatarImagesFolder[];
-
   // Clients of AccountTrackerService can implement this interface and register
   // with AddObserver() to learn about account information changes.
   class Observer {
diff --git a/components/signin/core/browser/account_tracker_service_unittest.cc b/components/signin/core/browser/account_tracker_service_unittest.cc
index fba578a9..4a12037e 100644
--- a/components/signin/core/browser/account_tracker_service_unittest.cc
+++ b/components/signin/core/browser/account_tracker_service_unittest.cc
@@ -636,13 +636,13 @@
   SimulateTokenAvailable(kAccountKeyAlpha);
   ReturnAccountInfoFetchSuccess(kAccountKeyAlpha);
 
-  std::string gaia_id = AccountKeyToGaiaId(kAccountKeyAlpha);
-  AccountInfo info = account_tracker()->FindAccountInfoByGaiaId(gaia_id);
+  const std::string gaia_id_alpha = AccountKeyToGaiaId(kAccountKeyAlpha);
+  AccountInfo info = account_tracker()->FindAccountInfoByGaiaId(gaia_id_alpha);
   EXPECT_EQ(AccountKeyToAccountId(kAccountKeyAlpha), info.account_id);
-  EXPECT_EQ(gaia_id, info.gaia);
+  EXPECT_EQ(gaia_id_alpha, info.gaia);
 
-  gaia_id = AccountKeyToGaiaId(kAccountKeyBeta);
-  info = account_tracker()->FindAccountInfoByGaiaId(gaia_id);
+  const std::string gaia_id_beta = AccountKeyToGaiaId(kAccountKeyBeta);
+  info = account_tracker()->FindAccountInfoByGaiaId(gaia_id_beta);
   EXPECT_EQ(std::string(), info.account_id);
 }
 
@@ -650,21 +650,21 @@
   SimulateTokenAvailable(kAccountKeyAlpha);
   ReturnAccountInfoFetchSuccess(kAccountKeyAlpha);
 
-  std::string email = AccountKeyToEmail(kAccountKeyAlpha);
-  AccountInfo info = account_tracker()->FindAccountInfoByEmail(email);
+  const std::string email_alpha = AccountKeyToEmail(kAccountKeyAlpha);
+  AccountInfo info = account_tracker()->FindAccountInfoByEmail(email_alpha);
   EXPECT_EQ(AccountKeyToAccountId(kAccountKeyAlpha), info.account_id);
-  EXPECT_EQ(email, info.email);
+  EXPECT_EQ(email_alpha, info.email);
 
   // Should also work with "canonically-equal" email addresses.
   info = account_tracker()->FindAccountInfoByEmail("Alpha@Gmail.COM");
   EXPECT_EQ(AccountKeyToAccountId(kAccountKeyAlpha), info.account_id);
-  EXPECT_EQ(email, info.email);
+  EXPECT_EQ(email_alpha, info.email);
   info = account_tracker()->FindAccountInfoByEmail("al.pha@gmail.com");
   EXPECT_EQ(AccountKeyToAccountId(kAccountKeyAlpha), info.account_id);
-  EXPECT_EQ(email, info.email);
+  EXPECT_EQ(email_alpha, info.email);
 
-  email = AccountKeyToEmail(kAccountKeyBeta);
-  info = account_tracker()->FindAccountInfoByEmail(email);
+  const std::string email_beta = AccountKeyToEmail(kAccountKeyBeta);
+  info = account_tracker()->FindAccountInfoByEmail(email_beta);
   EXPECT_EQ(std::string(), info.account_id);
 }
 
@@ -675,74 +675,68 @@
 
   // Create a tracker and add two accounts.  This should cause the accounts
   // to be saved to persistence.
-  {
-    ResetAccountTrackerWithPersistence(scoped_user_data_dir.GetPath());
-    SimulateTokenAvailable(kAccountKeyAlpha);
-    ReturnAccountInfoFetchSuccess(kAccountKeyAlpha);
-    ReturnAccountImageFetchSuccess(kAccountKeyAlpha);
-    SimulateTokenAvailable(kAccountKeyBeta);
-    ReturnAccountInfoFetchSuccess(kAccountKeyBeta);
-    ReturnAccountImageFetchSuccess(kAccountKeyBeta);
-  }
+  ResetAccountTrackerWithPersistence(scoped_user_data_dir.GetPath());
+  SimulateTokenAvailable(kAccountKeyAlpha);
+  ReturnAccountInfoFetchSuccess(kAccountKeyAlpha);
+  ReturnAccountImageFetchSuccess(kAccountKeyAlpha);
+  SimulateTokenAvailable(kAccountKeyBeta);
+  ReturnAccountInfoFetchSuccess(kAccountKeyBeta);
+  ReturnAccountImageFetchSuccess(kAccountKeyBeta);
 
   // Create a new tracker and make sure it loads the accounts (including the
   // images) correctly from persistence.
-  {
-    ResetAccountTrackerWithPersistence(scoped_user_data_dir.GetPath());
+  ResetAccountTrackerWithPersistence(scoped_user_data_dir.GetPath());
 
-    EXPECT_TRUE(observer()->CheckEvents({
-        TrackingEvent(UPDATED, AccountKeyToAccountId(kAccountKeyAlpha),
-                      AccountKeyToGaiaId(kAccountKeyAlpha)),
-        TrackingEvent(UPDATED, AccountKeyToAccountId(kAccountKeyBeta),
-                      AccountKeyToGaiaId(kAccountKeyBeta)),
-    }));
-    // Wait until all account images are loaded.
-    scoped_task_environment_.RunUntilIdle();
-    EXPECT_TRUE(observer()->CheckEvents({
-        TrackingEvent(IMAGE_UPDATED, AccountKeyToAccountId(kAccountKeyAlpha),
-                      AccountKeyToGaiaId(kAccountKeyAlpha)),
-        TrackingEvent(IMAGE_UPDATED, AccountKeyToAccountId(kAccountKeyBeta),
-                      AccountKeyToGaiaId(kAccountKeyBeta)),
-    }));
+  EXPECT_TRUE(observer()->CheckEvents({
+      TrackingEvent(UPDATED, AccountKeyToAccountId(kAccountKeyAlpha),
+                    AccountKeyToGaiaId(kAccountKeyAlpha)),
+      TrackingEvent(UPDATED, AccountKeyToAccountId(kAccountKeyBeta),
+                    AccountKeyToGaiaId(kAccountKeyBeta)),
+  }));
+  // Wait until all account images are loaded.
+  scoped_task_environment_.RunUntilIdle();
+  EXPECT_TRUE(observer()->CheckEvents({
+      TrackingEvent(IMAGE_UPDATED, AccountKeyToAccountId(kAccountKeyAlpha),
+                    AccountKeyToGaiaId(kAccountKeyAlpha)),
+      TrackingEvent(IMAGE_UPDATED, AccountKeyToAccountId(kAccountKeyBeta),
+                    AccountKeyToGaiaId(kAccountKeyBeta)),
+  }));
 
-    std::vector<AccountInfo> infos = account_tracker()->GetAccounts();
-    ASSERT_EQ(2u, infos.size());
-    CheckAccountDetails(kAccountKeyAlpha, infos[0]);
-    CheckAccountDetails(kAccountKeyBeta, infos[1]);
+  std::vector<AccountInfo> infos = account_tracker()->GetAccounts();
+  ASSERT_EQ(2u, infos.size());
+  CheckAccountDetails(kAccountKeyAlpha, infos[0]);
+  CheckAccountDetails(kAccountKeyBeta, infos[1]);
 
-    // Remove an account.
-    // This will allow testing removal as well as child accounts which is only
-    // allowed for a single account.
-    SimulateTokenRevoked(kAccountKeyAlpha);
+  // Remove an account.
+  // This will allow testing removal as well as child accounts which is only
+  // allowed for a single account.
+  SimulateTokenRevoked(kAccountKeyAlpha);
 #if defined(OS_ANDROID)
-    account_fetcher()->SetIsChildAccount(AccountKeyToAccountId(kAccountKeyBeta),
-                                         true);
+  account_fetcher()->SetIsChildAccount(AccountKeyToAccountId(kAccountKeyBeta),
+                                       true);
 #else
-    account_tracker()->SetIsChildAccount(AccountKeyToAccountId(kAccountKeyBeta),
-                                         true);
+  account_tracker()->SetIsChildAccount(AccountKeyToAccountId(kAccountKeyBeta),
+                                       true);
 #endif
 
 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
-    account_tracker()->SetIsAdvancedProtectionAccount(
-        AccountKeyToAccountId(kAccountKeyBeta), true);
+  account_tracker()->SetIsAdvancedProtectionAccount(
+      AccountKeyToAccountId(kAccountKeyBeta), true);
 #endif
-  }
 
   // Create a new tracker and make sure it loads the single account from
   // persistence. Also verify it is a child account.
-  {
-    ResetAccountTrackerWithPersistence(scoped_user_data_dir.GetPath());
+  ResetAccountTrackerWithPersistence(scoped_user_data_dir.GetPath());
 
-    std::vector<AccountInfo> infos = account_tracker()->GetAccounts();
-    ASSERT_EQ(1u, infos.size());
-    CheckAccountDetails(kAccountKeyBeta, infos[0]);
-    EXPECT_TRUE(infos[0].is_child_account);
+  infos = account_tracker()->GetAccounts();
+  ASSERT_EQ(1u, infos.size());
+  CheckAccountDetails(kAccountKeyBeta, infos[0]);
+  EXPECT_TRUE(infos[0].is_child_account);
 #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) && !defined(OS_IOS)
-    EXPECT_TRUE(infos[0].is_under_advanced_protection);
+  EXPECT_TRUE(infos[0].is_under_advanced_protection);
 #else
-    EXPECT_FALSE(infos[0].is_under_advanced_protection);
+  EXPECT_FALSE(infos[0].is_under_advanced_protection);
 #endif
-  }
 }
 
 TEST_F(AccountTrackerServiceTest, SeedAccountInfo) {
@@ -807,62 +801,54 @@
 TEST_F(AccountTrackerServiceTest, UpgradeToFullAccountInfo) {
   // Start by simulating an incomplete account info and let it be saved to
   // prefs.
-  {
-    ResetAccountTracker();
-    SimulateTokenAvailable(kAccountKeyIncomplete);
-    ReturnAccountInfoFetchSuccessIncomplete(kAccountKeyIncomplete);
-  }
+  ResetAccountTracker();
+  SimulateTokenAvailable(kAccountKeyIncomplete);
+  ReturnAccountInfoFetchSuccessIncomplete(kAccountKeyIncomplete);
 
-  {
-    ResetAccountTracker();
+  ResetAccountTracker();
 
-    // Validate that the loaded AccountInfo from prefs is considered invalid.
-    std::vector<AccountInfo> infos = account_tracker()->GetAccounts();
-    ASSERT_EQ(1u, infos.size());
-    EXPECT_FALSE(infos[0].IsValid());
+  // Validate that the loaded AccountInfo from prefs is considered invalid.
+  std::vector<AccountInfo> infos = account_tracker()->GetAccounts();
+  ASSERT_EQ(1u, infos.size());
+  EXPECT_FALSE(infos[0].IsValid());
 
-    // Simulate the same account getting a refresh token with all the info.
-    SimulateTokenAvailable(kAccountKeyIncomplete);
-    ReturnAccountInfoFetchSuccess(kAccountKeyIncomplete);
+  // Simulate the same account getting a refresh token with all the info.
+  SimulateTokenAvailable(kAccountKeyIncomplete);
+  ReturnAccountInfoFetchSuccess(kAccountKeyIncomplete);
 
-    // Validate that the account is now considered valid.
-    infos = account_tracker()->GetAccounts();
-    ASSERT_EQ(1u, infos.size());
-    EXPECT_TRUE(infos[0].IsValid());
-  }
+  // Validate that the account is now considered valid.
+  infos = account_tracker()->GetAccounts();
+  ASSERT_EQ(1u, infos.size());
+  EXPECT_TRUE(infos[0].IsValid());
 
   // Reinstantiate a tracker to validate that the AccountInfo saved to prefs
   // is now the upgraded one, considered valid.
-  {
-    ResetAccountTrackerNetworkDisabled();
+  ResetAccountTrackerNetworkDisabled();
 
-    EXPECT_TRUE(observer()->CheckEvents({
-        TrackingEvent(UPDATED, AccountKeyToAccountId(kAccountKeyIncomplete),
-                      AccountKeyToGaiaId(kAccountKeyIncomplete)),
-    }));
+  EXPECT_TRUE(observer()->CheckEvents({
+      TrackingEvent(UPDATED, AccountKeyToAccountId(kAccountKeyIncomplete),
+                    AccountKeyToGaiaId(kAccountKeyIncomplete)),
+  }));
 
-    // Enabling network fetches shouldn't cause any actual fetch since the
-    // AccountInfos loaded from prefs should be valid.
-    account_fetcher()->EnableNetworkFetchesForTest();
+  // Enabling network fetches shouldn't cause any actual fetch since the
+  // AccountInfos loaded from prefs should be valid.
+  account_fetcher()->EnableNetworkFetchesForTest();
 
-    std::vector<AccountInfo> infos = account_tracker()->GetAccounts();
-    ASSERT_EQ(1u, infos.size());
-    EXPECT_TRUE(infos[0].IsValid());
-    // Check that no network fetches were made.
-    EXPECT_TRUE(observer()->CheckEvents({}));
-  }
+  infos = account_tracker()->GetAccounts();
+  ASSERT_EQ(1u, infos.size());
+  EXPECT_TRUE(infos[0].IsValid());
+  // Check that no network fetches were made.
+  EXPECT_TRUE(observer()->CheckEvents({}));
 }
 
 TEST_F(AccountTrackerServiceTest, TimerRefresh) {
   // Start by creating a tracker and adding a couple accounts to be persisted
   // to prefs.
-  {
-    ResetAccountTracker();
-    SimulateTokenAvailable(kAccountKeyAlpha);
-    ReturnAccountInfoFetchSuccess(kAccountKeyAlpha);
-    SimulateTokenAvailable(kAccountKeyBeta);
-    ReturnAccountInfoFetchSuccess(kAccountKeyBeta);
-  }
+  ResetAccountTracker();
+  SimulateTokenAvailable(kAccountKeyAlpha);
+  ReturnAccountInfoFetchSuccess(kAccountKeyAlpha);
+  SimulateTokenAvailable(kAccountKeyBeta);
+  ReturnAccountInfoFetchSuccess(kAccountKeyBeta);
 
   // Rewind the time by half a day, which shouldn't be enough to trigger a
   // network refresh.
@@ -872,18 +858,16 @@
 
   // Instantiate a new ATS, making sure the persisted accounts are still there
   // and that no network fetches happen.
-  {
-    ResetAccountTrackerNetworkDisabled();
+  ResetAccountTrackerNetworkDisabled();
 
-    EXPECT_TRUE(account_fetcher()->IsAllUserInfoFetched());
-    std::vector<AccountInfo> infos = account_tracker()->GetAccounts();
-    ASSERT_EQ(2u, infos.size());
-    EXPECT_TRUE(infos[0].IsValid());
-    EXPECT_TRUE(infos[1].IsValid());
+  EXPECT_TRUE(account_fetcher()->IsAllUserInfoFetched());
+  std::vector<AccountInfo> infos = account_tracker()->GetAccounts();
+  ASSERT_EQ(2u, infos.size());
+  EXPECT_TRUE(infos[0].IsValid());
+  EXPECT_TRUE(infos[1].IsValid());
 
-    account_fetcher()->EnableNetworkFetchesForTest();
-    EXPECT_TRUE(account_fetcher()->IsAllUserInfoFetched());
-  }
+  account_fetcher()->EnableNetworkFetchesForTest();
+  EXPECT_TRUE(account_fetcher()->IsAllUserInfoFetched());
 
   // Rewind the last updated time enough to trigger a network refresh.
   fake_update = base::Time::Now() - base::TimeDelta::FromHours(25);
@@ -892,18 +876,16 @@
 
   // Instantiate a new tracker and validate that even though the AccountInfos
   // are still valid, the network fetches are started.
-  {
-    ResetAccountTrackerNetworkDisabled();
+  ResetAccountTrackerNetworkDisabled();
 
-    EXPECT_TRUE(account_fetcher()->IsAllUserInfoFetched());
-    std::vector<AccountInfo> infos = account_tracker()->GetAccounts();
-    ASSERT_EQ(2u, infos.size());
-    EXPECT_TRUE(infos[0].IsValid());
-    EXPECT_TRUE(infos[1].IsValid());
+  EXPECT_TRUE(account_fetcher()->IsAllUserInfoFetched());
+  infos = account_tracker()->GetAccounts();
+  ASSERT_EQ(2u, infos.size());
+  EXPECT_TRUE(infos[0].IsValid());
+  EXPECT_TRUE(infos[1].IsValid());
 
-    account_fetcher()->EnableNetworkFetchesForTest();
-    EXPECT_FALSE(account_fetcher()->IsAllUserInfoFetched());
-  }
+  account_fetcher()->EnableNetworkFetchesForTest();
+  EXPECT_FALSE(account_fetcher()->IsAllUserInfoFetched());
 }
 
 TEST_F(AccountTrackerServiceTest, LegacyDottedAccountIds) {
@@ -914,20 +896,18 @@
   // Start by creating a tracker and adding an account with a dotted account
   // id because of an old bug in token service.  The token service would also
   // add a correct non-dotted account id for the same account.
-  {
-    ResetAccountTracker();
+  ResetAccountTracker();
 
-    SimulateTokenAvailable(kAccountKeyFooDotBar);
-    SimulateTokenAvailable(kAccountKeyFooBar);
-    ReturnAccountInfoFetchSuccess(kAccountKeyFooDotBar);
-    ReturnAccountInfoFetchSuccess(kAccountKeyFooBar);
+  SimulateTokenAvailable(kAccountKeyFooDotBar);
+  SimulateTokenAvailable(kAccountKeyFooBar);
+  ReturnAccountInfoFetchSuccess(kAccountKeyFooDotBar);
+  ReturnAccountInfoFetchSuccess(kAccountKeyFooBar);
 
-    EXPECT_TRUE(account_fetcher()->IsAllUserInfoFetched());
-    std::vector<AccountInfo> infos = account_tracker()->GetAccounts();
-    ASSERT_EQ(2u, infos.size());
-    EXPECT_EQ(AccountKeyToEmail(kAccountKeyFooDotBar), infos[0].email);
-    EXPECT_EQ(AccountKeyToEmail(kAccountKeyFooBar), infos[1].email);
-  }
+  EXPECT_TRUE(account_fetcher()->IsAllUserInfoFetched());
+  std::vector<AccountInfo> infos = account_tracker()->GetAccounts();
+  ASSERT_EQ(2u, infos.size());
+  EXPECT_EQ(AccountKeyToEmail(kAccountKeyFooDotBar), infos[0].email);
+  EXPECT_EQ(AccountKeyToEmail(kAccountKeyFooBar), infos[1].email);
 
   // Remove the bad account now from the token service to simulate that it
   // has been "fixed".
@@ -935,239 +915,214 @@
 
   // Instantiate a new tracker and validate that it has only one account, and
   // it is the correct non dotted one.
-  {
     ResetAccountTrackerNetworkDisabled();
 
     EXPECT_TRUE(account_fetcher()->IsAllUserInfoFetched());
-    std::vector<AccountInfo> infos = account_tracker()->GetAccounts();
+    infos = account_tracker()->GetAccounts();
     ASSERT_EQ(1u, infos.size());
     EXPECT_EQ(AccountKeyToEmail(kAccountKeyFooBar), infos[0].email);
-  }
 }
 
 TEST_F(AccountTrackerServiceTest, NoDeprecatedServiceFlags) {
-  std::string email_alpha = AccountKeyToEmail(kAccountKeyAlpha);
-  std::string gaia_alpha = AccountKeyToGaiaId(kAccountKeyAlpha);
+  const std::string email_alpha = AccountKeyToEmail(kAccountKeyAlpha);
+  const std::string gaia_alpha = AccountKeyToGaiaId(kAccountKeyAlpha);
 
-  {
-    ListPrefUpdate update(prefs(), AccountTrackerService::kAccountInfoPref);
+  ListPrefUpdate update(prefs(), AccountTrackerService::kAccountInfoPref);
 
-    std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-    dict->SetString("account_id", email_alpha);
-    dict->SetString("email", email_alpha);
-    dict->SetString("gaia", gaia_alpha);
-    update->Append(std::move(dict));
-  }
+  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+  dict->SetString("account_id", email_alpha);
+  dict->SetString("email", email_alpha);
+  dict->SetString("gaia", gaia_alpha);
+  update->Append(std::move(dict));
 
-  {
-    base::HistogramTester tester;
+  base::HistogramTester tester;
 
-    ResetAccountTracker();
-    tester.ExpectBucketCount(
-        "Signin.AccountTracker.DeprecatedServiceFlagDeleted", false, 1);
-  }
+  ResetAccountTracker();
+  tester.ExpectBucketCount("Signin.AccountTracker.DeprecatedServiceFlagDeleted",
+                           false, 1);
 }
 
 TEST_F(AccountTrackerServiceTest, MigrateDeprecatedServiceFlags) {
-  std::string email_alpha = AccountKeyToEmail(kAccountKeyAlpha);
-  std::string gaia_alpha = AccountKeyToGaiaId(kAccountKeyAlpha);
+  const std::string email_alpha = AccountKeyToEmail(kAccountKeyAlpha);
+  const std::string gaia_alpha = AccountKeyToGaiaId(kAccountKeyAlpha);
 
-  {
-    ListPrefUpdate update(prefs(), AccountTrackerService::kAccountInfoPref);
+  ListPrefUpdate update(prefs(), AccountTrackerService::kAccountInfoPref);
 
-    std::unique_ptr<base::ListValue> service_flags(new base::ListValue());
-    service_flags->Append(std::make_unique<base::Value>("uca"));
+  std::unique_ptr<base::ListValue> service_flags(new base::ListValue());
+  service_flags->Append(std::make_unique<base::Value>("uca"));
 
-    std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-    dict->SetString("account_id", email_alpha);
-    dict->SetString("email", email_alpha);
-    dict->SetString("gaia", gaia_alpha);
-    dict->SetList("service_flags", std::move(service_flags));
-    update->Append(std::move(dict));
-  }
+  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+  dict->SetString("account_id", email_alpha);
+  dict->SetString("email", email_alpha);
+  dict->SetString("gaia", gaia_alpha);
+  dict->SetList("service_flags", std::move(service_flags));
+  update->Append(std::move(dict));
 
-  {
-    base::HistogramTester tester;
+  base::HistogramTester tester;
 
-    ResetAccountTracker();
-    tester.ExpectBucketCount(
-        "Signin.AccountTracker.DeprecatedServiceFlagDeleted", true, 1);
-  }
+  ResetAccountTracker();
+  tester.ExpectBucketCount("Signin.AccountTracker.DeprecatedServiceFlagDeleted",
+                           true, 1);
 }
 
 TEST_F(AccountTrackerServiceTest, MigrateAccountIdToGaiaId) {
   if (!AccountTrackerService::IsMigrationSupported())
     return;
 
-  std::string email_alpha = AccountKeyToEmail(kAccountKeyAlpha);
-  std::string gaia_alpha = AccountKeyToGaiaId(kAccountKeyAlpha);
-  std::string email_beta = AccountKeyToEmail(kAccountKeyBeta);
-  std::string gaia_beta = AccountKeyToGaiaId(kAccountKeyBeta);
+  const std::string email_alpha = AccountKeyToEmail(kAccountKeyAlpha);
+  const std::string gaia_alpha = AccountKeyToGaiaId(kAccountKeyAlpha);
+  const std::string email_beta = AccountKeyToEmail(kAccountKeyBeta);
+  const std::string gaia_beta = AccountKeyToGaiaId(kAccountKeyBeta);
 
-  {
-    ListPrefUpdate update(prefs(), AccountTrackerService::kAccountInfoPref);
+  ListPrefUpdate update(prefs(), AccountTrackerService::kAccountInfoPref);
 
-    std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-    dict->SetString("account_id", email_alpha);
-    dict->SetString("email", email_alpha);
-    dict->SetString("gaia", gaia_alpha);
-    update->Append(std::move(dict));
+  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+  dict->SetString("account_id", email_alpha);
+  dict->SetString("email", email_alpha);
+  dict->SetString("gaia", gaia_alpha);
+  update->Append(std::move(dict));
 
-    dict.reset(new base::DictionaryValue());
-    dict->SetString("account_id", email_beta);
-    dict->SetString("email", email_beta);
-    dict->SetString("gaia", gaia_beta);
-    update->Append(std::move(dict));
-  }
+  dict.reset(new base::DictionaryValue());
+  dict->SetString("account_id", email_beta);
+  dict->SetString("email", email_beta);
+  dict->SetString("gaia", gaia_beta);
+  update->Append(std::move(dict));
 
-  {
-    base::HistogramTester tester;
-    ResetAccountTracker();
+  base::HistogramTester tester;
+  ResetAccountTracker();
 
-    tester.ExpectBucketCount("Signin.AccountTracker.GaiaIdMigrationState",
-                             AccountTrackerService::MIGRATION_IN_PROGRESS, 1);
-    EXPECT_EQ(account_tracker()->GetMigrationState(),
-              AccountTrackerService::MIGRATION_IN_PROGRESS);
+  tester.ExpectBucketCount("Signin.AccountTracker.GaiaIdMigrationState",
+                           AccountTrackerService::MIGRATION_IN_PROGRESS, 1);
+  EXPECT_EQ(account_tracker()->GetMigrationState(),
+            AccountTrackerService::MIGRATION_IN_PROGRESS);
 
-    AccountInfo account_info = account_tracker()->GetAccountInfo(gaia_alpha);
-    EXPECT_EQ(account_info.account_id, gaia_alpha);
-    EXPECT_EQ(account_info.gaia, gaia_alpha);
-    EXPECT_EQ(account_info.email, email_alpha);
+  AccountInfo account_info = account_tracker()->GetAccountInfo(gaia_alpha);
+  EXPECT_EQ(account_info.account_id, gaia_alpha);
+  EXPECT_EQ(account_info.gaia, gaia_alpha);
+  EXPECT_EQ(account_info.email, email_alpha);
 
-    account_info = account_tracker()->GetAccountInfo(gaia_beta);
-    EXPECT_EQ(account_info.account_id, gaia_beta);
-    EXPECT_EQ(account_info.gaia, gaia_beta);
-    EXPECT_EQ(account_info.email, email_beta);
+  account_info = account_tracker()->GetAccountInfo(gaia_beta);
+  EXPECT_EQ(account_info.account_id, gaia_beta);
+  EXPECT_EQ(account_info.gaia, gaia_beta);
+  EXPECT_EQ(account_info.email, email_beta);
 
-    std::vector<AccountInfo> accounts = account_tracker()->GetAccounts();
-    EXPECT_EQ(2u, accounts.size());
-  }
+  std::vector<AccountInfo> accounts = account_tracker()->GetAccounts();
+  EXPECT_EQ(2u, accounts.size());
 }
 
 TEST_F(AccountTrackerServiceTest, CanNotMigrateAccountIdToGaiaId) {
   if (!AccountTrackerService::IsMigrationSupported())
     return;
 
-  std::string email_alpha = AccountKeyToEmail(kAccountKeyAlpha);
-  std::string gaia_alpha = AccountKeyToGaiaId(kAccountKeyAlpha);
-  std::string email_beta = AccountKeyToEmail(kAccountKeyBeta);
+  const std::string email_alpha = AccountKeyToEmail(kAccountKeyAlpha);
+  const std::string gaia_alpha = AccountKeyToGaiaId(kAccountKeyAlpha);
+  const std::string email_beta = AccountKeyToEmail(kAccountKeyBeta);
 
-  {
-    ListPrefUpdate update(prefs(), AccountTrackerService::kAccountInfoPref);
+  ListPrefUpdate update(prefs(), AccountTrackerService::kAccountInfoPref);
 
-    std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-    dict->SetString("account_id", email_alpha);
-    dict->SetString("email", email_alpha);
-    dict->SetString("gaia", gaia_alpha);
-    update->Append(std::move(dict));
+  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+  dict->SetString("account_id", email_alpha);
+  dict->SetString("email", email_alpha);
+  dict->SetString("gaia", gaia_alpha);
+  update->Append(std::move(dict));
 
-    dict.reset(new base::DictionaryValue());
-    dict->SetString("account_id", email_beta);
-    dict->SetString("email", email_beta);
-    dict->SetString("gaia", "");
-    update->Append(std::move(dict));
-  }
+  dict.reset(new base::DictionaryValue());
+  dict->SetString("account_id", email_beta);
+  dict->SetString("email", email_beta);
+  dict->SetString("gaia", "");
+  update->Append(std::move(dict));
 
-  {
-    base::HistogramTester tester;
-    ResetAccountTracker();
+  base::HistogramTester tester;
+  ResetAccountTracker();
 
-    tester.ExpectBucketCount("Signin.AccountTracker.GaiaIdMigrationState",
-                             AccountTrackerService::MIGRATION_NOT_STARTED, 1);
-    EXPECT_EQ(account_tracker()->GetMigrationState(),
-              AccountTrackerService::MIGRATION_NOT_STARTED);
+  tester.ExpectBucketCount("Signin.AccountTracker.GaiaIdMigrationState",
+                           AccountTrackerService::MIGRATION_NOT_STARTED, 1);
+  EXPECT_EQ(account_tracker()->GetMigrationState(),
+            AccountTrackerService::MIGRATION_NOT_STARTED);
 
-    AccountInfo account_info = account_tracker()->GetAccountInfo(email_alpha);
-    EXPECT_EQ(account_info.account_id, email_alpha);
-    EXPECT_EQ(account_info.gaia, gaia_alpha);
-    EXPECT_EQ(account_info.email, email_alpha);
+  AccountInfo account_info = account_tracker()->GetAccountInfo(email_alpha);
+  EXPECT_EQ(account_info.account_id, email_alpha);
+  EXPECT_EQ(account_info.gaia, gaia_alpha);
+  EXPECT_EQ(account_info.email, email_alpha);
 
-    account_info = account_tracker()->GetAccountInfo(email_beta);
-    EXPECT_EQ(account_info.account_id, email_beta);
-    EXPECT_EQ(account_info.email, email_beta);
+  account_info = account_tracker()->GetAccountInfo(email_beta);
+  EXPECT_EQ(account_info.account_id, email_beta);
+  EXPECT_EQ(account_info.email, email_beta);
 
-    std::vector<AccountInfo> accounts = account_tracker()->GetAccounts();
-    EXPECT_EQ(2u, accounts.size());
-  }
+  std::vector<AccountInfo> accounts = account_tracker()->GetAccounts();
+  EXPECT_EQ(2u, accounts.size());
 }
 
 TEST_F(AccountTrackerServiceTest, GaiaIdMigrationCrashInTheMiddle) {
   if (!AccountTrackerService::IsMigrationSupported())
     return;
 
-  std::string email_alpha = AccountKeyToEmail(kAccountKeyAlpha);
-  std::string gaia_alpha = AccountKeyToGaiaId(kAccountKeyAlpha);
-  std::string email_beta = AccountKeyToEmail(kAccountKeyBeta);
-  std::string gaia_beta = AccountKeyToGaiaId(kAccountKeyBeta);
+  const std::string email_alpha = AccountKeyToEmail(kAccountKeyAlpha);
+  const std::string gaia_alpha = AccountKeyToGaiaId(kAccountKeyAlpha);
+  const std::string email_beta = AccountKeyToEmail(kAccountKeyBeta);
+  const std::string gaia_beta = AccountKeyToGaiaId(kAccountKeyBeta);
 
-  {
-    ListPrefUpdate update(prefs(), AccountTrackerService::kAccountInfoPref);
+  ListPrefUpdate update(prefs(), AccountTrackerService::kAccountInfoPref);
 
-    std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
-    dict->SetString("account_id", email_alpha);
-    dict->SetString("email", email_alpha);
-    dict->SetString("gaia", gaia_alpha);
-    update->Append(std::move(dict));
+  std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue());
+  dict->SetString("account_id", email_alpha);
+  dict->SetString("email", email_alpha);
+  dict->SetString("gaia", gaia_alpha);
+  update->Append(std::move(dict));
 
-    dict.reset(new base::DictionaryValue());
-    dict->SetString("account_id", email_beta);
-    dict->SetString("email", email_beta);
-    dict->SetString("gaia", gaia_beta);
-    update->Append(std::move(dict));
+  dict.reset(new base::DictionaryValue());
+  dict->SetString("account_id", email_beta);
+  dict->SetString("email", email_beta);
+  dict->SetString("gaia", gaia_beta);
+  update->Append(std::move(dict));
 
-    // Succeed miggrated account.
-    dict.reset(new base::DictionaryValue());
-    dict->SetString("account_id", gaia_alpha);
-    dict->SetString("email", email_alpha);
-    dict->SetString("gaia", gaia_alpha);
-    update->Append(std::move(dict));
-  }
+  // Succeed miggrated account.
+  dict.reset(new base::DictionaryValue());
+  dict->SetString("account_id", gaia_alpha);
+  dict->SetString("email", email_alpha);
+  dict->SetString("gaia", gaia_alpha);
+  update->Append(std::move(dict));
 
-  {
-    base::HistogramTester tester;
-    ResetAccountTracker();
+  base::HistogramTester tester;
+  ResetAccountTracker();
 
-    tester.ExpectBucketCount("Signin.AccountTracker.GaiaIdMigrationState",
-                             AccountTrackerService::MIGRATION_IN_PROGRESS, 1);
-    EXPECT_EQ(account_tracker()->GetMigrationState(),
-              AccountTrackerService::MIGRATION_IN_PROGRESS);
+  tester.ExpectBucketCount("Signin.AccountTracker.GaiaIdMigrationState",
+                           AccountTrackerService::MIGRATION_IN_PROGRESS, 1);
+  EXPECT_EQ(account_tracker()->GetMigrationState(),
+            AccountTrackerService::MIGRATION_IN_PROGRESS);
 
-    AccountInfo account_info = account_tracker()->GetAccountInfo(gaia_alpha);
-    EXPECT_EQ(account_info.account_id, gaia_alpha);
-    EXPECT_EQ(account_info.gaia, gaia_alpha);
-    EXPECT_EQ(account_info.email, email_alpha);
+  AccountInfo account_info = account_tracker()->GetAccountInfo(gaia_alpha);
+  EXPECT_EQ(account_info.account_id, gaia_alpha);
+  EXPECT_EQ(account_info.gaia, gaia_alpha);
+  EXPECT_EQ(account_info.email, email_alpha);
 
-    account_info = account_tracker()->GetAccountInfo(gaia_beta);
-    EXPECT_EQ(account_info.account_id, gaia_beta);
-    EXPECT_EQ(account_info.gaia, gaia_beta);
-    EXPECT_EQ(account_info.email, email_beta);
+  account_info = account_tracker()->GetAccountInfo(gaia_beta);
+  EXPECT_EQ(account_info.account_id, gaia_beta);
+  EXPECT_EQ(account_info.gaia, gaia_beta);
+  EXPECT_EQ(account_info.email, email_beta);
 
-    std::vector<AccountInfo> accounts = account_tracker()->GetAccounts();
-    EXPECT_EQ(2u, accounts.size());
-  }
+  std::vector<AccountInfo> accounts = account_tracker()->GetAccounts();
+  EXPECT_EQ(2u, accounts.size());
 
-  {
-    base::HistogramTester tester;
-    ResetAccountTracker();
+  ResetAccountTracker();
 
-    tester.ExpectBucketCount("Signin.AccountTracker.GaiaIdMigrationState",
-                             AccountTrackerService::MIGRATION_DONE, 1);
-    EXPECT_EQ(account_tracker()->GetMigrationState(),
-              AccountTrackerService::MIGRATION_DONE);
+  tester.ExpectBucketCount("Signin.AccountTracker.GaiaIdMigrationState",
+                           AccountTrackerService::MIGRATION_DONE, 1);
+  EXPECT_EQ(account_tracker()->GetMigrationState(),
+            AccountTrackerService::MIGRATION_DONE);
 
-    AccountInfo account_info = account_tracker()->GetAccountInfo(gaia_alpha);
-    EXPECT_EQ(account_info.account_id, gaia_alpha);
-    EXPECT_EQ(account_info.gaia, gaia_alpha);
-    EXPECT_EQ(account_info.email, email_alpha);
+  account_info = account_tracker()->GetAccountInfo(gaia_alpha);
+  EXPECT_EQ(account_info.account_id, gaia_alpha);
+  EXPECT_EQ(account_info.gaia, gaia_alpha);
+  EXPECT_EQ(account_info.email, email_alpha);
 
-    account_info = account_tracker()->GetAccountInfo(gaia_beta);
-    EXPECT_EQ(account_info.account_id, gaia_beta);
-    EXPECT_EQ(account_info.gaia, gaia_beta);
-    EXPECT_EQ(account_info.email, email_beta);
+  account_info = account_tracker()->GetAccountInfo(gaia_beta);
+  EXPECT_EQ(account_info.account_id, gaia_beta);
+  EXPECT_EQ(account_info.gaia, gaia_beta);
+  EXPECT_EQ(account_info.email, email_beta);
 
-    std::vector<AccountInfo> accounts = account_tracker()->GetAccounts();
-    EXPECT_EQ(2u, accounts.size());
-  }
+  accounts = account_tracker()->GetAccounts();
+  EXPECT_EQ(2u, accounts.size());
 }
 
 TEST_F(AccountTrackerServiceTest, ChildAccountBasic) {
diff --git a/components/signin/core/browser/gaia_cookie_manager_service.cc b/components/signin/core/browser/gaia_cookie_manager_service.cc
index ce01f1f..d34a0dc 100644
--- a/components/signin/core/browser/gaia_cookie_manager_service.cc
+++ b/components/signin/core/browser/gaia_cookie_manager_service.cc
@@ -70,6 +70,12 @@
 // accounts have changed in the content-area.
 const char* const kGaiaCookieName = "APISID";
 
+// Records metrics for ListAccounts failures.
+void RecordListAccountsFailure(GoogleServiceAuthError::State error_state) {
+  UMA_HISTOGRAM_ENUMERATION("Signin.ListAccountsFailure", error_state,
+                            GoogleServiceAuthError::NUM_STATES);
+}
+
 }  // namespace
 
 GaiaCookieManagerService::GaiaCookieRequest::GaiaCookieRequest(
@@ -818,6 +824,8 @@
     return;
   }
 
+  RecordListAccountsFailure(GoogleServiceAuthError::NONE);
+
   for (gaia::ListedAccount& account : listed_accounts_) {
     DCHECK(account.id.empty());
     account.id = AccountTrackerService::PickAccountIdForAccount(
@@ -855,8 +863,7 @@
     return;
   }
 
-  UMA_HISTOGRAM_ENUMERATION("Signin.ListAccountsFailure",
-      error.state(), GoogleServiceAuthError::NUM_STATES);
+  RecordListAccountsFailure(error.state());
   for (auto& observer : observer_list_) {
     observer.OnGaiaAccountsInCookieUpdated(listed_accounts_,
                                            signed_out_accounts_, error);
diff --git a/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc b/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
index bf19726..8763e83 100644
--- a/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
+++ b/components/sync/model_impl/client_tag_based_model_type_processor_unittest.cc
@@ -367,7 +367,7 @@
 };
 
 // Test that an initial sync handles local and remote items properly.
-TEST_F(ClientTagBasedModelTypeProcessorTest, InitialSync) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldMergeLocalAndRemoteChanges) {
   ModelReadyToSync();
   OnSyncStarting();
 
@@ -396,7 +396,7 @@
 }
 
 // Test that an initial sync filters out tombstones in the processor.
-TEST_F(ClientTagBasedModelTypeProcessorTest, InitialSyncWithTombstone) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldFilterOutInitialTombstones) {
   ModelReadyToSync();
   OnSyncStarting();
 
@@ -415,7 +415,7 @@
 
 // Test that an initial sync filters out updates for root nodes in the
 // processor.
-TEST_F(ClientTagBasedModelTypeProcessorTest, InitialSyncWithRootNode) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldFilterOutInitialRootNodes) {
   ModelReadyToSync();
   OnSyncStarting();
 
@@ -428,7 +428,7 @@
 }
 
 // Test that subsequent starts don't call MergeSyncData.
-TEST_F(ClientTagBasedModelTypeProcessorTest, NonInitialSync) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldApplyIncrementalUpdates) {
   // This sets initial_sync_done to true.
   InitializeToMetadataLoaded();
 
@@ -441,12 +441,13 @@
   OnSyncStarting();
   worker()->UpdateFromServer(kHash2, GenerateSpecifics(kKey2, kValue2));
   EXPECT_EQ(0, bridge()->merge_call_count());
+  EXPECT_EQ(1, bridge()->apply_call_count());
   EXPECT_EQ(2U, db().data_count());
   EXPECT_EQ(2U, db().metadata_count());
 }
 
 // Test that an error during the merge is propagated to the error handler.
-TEST_F(ClientTagBasedModelTypeProcessorTest, MergeError) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldReportErrorDuringMerge) {
   ModelReadyToSync();
   OnSyncStarting();
 
@@ -456,7 +457,7 @@
 }
 
 // Test that errors before it's called are passed to |start_callback| correctly.
-TEST_F(ClientTagBasedModelTypeProcessorTest, StartErrors) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldDeferErrorsBeforeStart) {
   type_processor()->ReportError({FROM_HERE, "boom"});
   ExpectError();
   OnSyncStarting();
@@ -499,7 +500,7 @@
 // - Optionally, a put or delete happens to the item.
 //
 // This results in 1 + 6 = 7 orderings of the events.
-TEST_F(ClientTagBasedModelTypeProcessorTest, LoadPendingCommit) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldLoadDataForPendingCommit) {
   // Connect, data.
   EntitySpecifics specifics2 = ResetStateWriteItem(kKey1, kValue1);
   InitializeToMetadataLoaded();
@@ -572,7 +573,7 @@
 }
 
 // Tests cases where pending data loads synchronously.
-TEST_F(ClientTagBasedModelTypeProcessorTest, LoadPendingSynchronous) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldHandleSynchronousDataLoad) {
   // Model, sync.
   EntitySpecifics specifics1 = ResetStateWriteItem(kKey1, kValue1);
   bridge()->ExpectSynchronousDataCallback();
@@ -600,7 +601,7 @@
 //   handled properly).
 //
 // This results in 1 + 4 = 5 orderings of the events.
-TEST_F(ClientTagBasedModelTypeProcessorTest, LoadPendingDelete) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldLoadPendingDelete) {
   // Connect.
   ResetStateDeleteItem(kKey1, kValue1);
   InitializeToMetadataLoaded();
@@ -646,7 +647,8 @@
 }
 
 // Test that loading a committed item does not queue another commit.
-TEST_F(ClientTagBasedModelTypeProcessorTest, LoadCommited) {
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldNotQueueAnotherCommitIfAlreadyCommitted) {
   InitializeToReadyState();
   WriteItemAndAck(kKey1, kValue1);
   ResetState(true);
@@ -659,7 +661,7 @@
 
 // Creates a new item locally.
 // Thoroughly tests the data generated by a local item creation.
-TEST_F(ClientTagBasedModelTypeProcessorTest, LocalCreateItem) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldCommitLocalCreation) {
   InitializeToReadyState();
   EXPECT_EQ(0U, worker()->GetNumPendingCommits());
 
@@ -703,7 +705,7 @@
 
 // Test that an error applying metadata changes from a commit response is
 // propagated to the error handler.
-TEST_F(ClientTagBasedModelTypeProcessorTest, ErrorApplyingAck) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldReportErrorApplyingAck) {
   InitializeToReadyState();
   bridge()->WriteItem(kKey1, kValue1);
   bridge()->ErrorOnNextCall();
@@ -713,7 +715,8 @@
 
 // The purpose of this test case is to test setting |client_tag_hash| and |id|
 // on the EntityData object as we pass it into the Put method of the processor.
-TEST_F(ClientTagBasedModelTypeProcessorTest, LocalUpdateItemWithOverrides) {
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldOverrideFieldsForLocalUpdate) {
   const std::string kId1 = "cid1";
   const std::string kId2 = "cid2";
 
@@ -774,11 +777,11 @@
 
 // Creates a new local item then modifies it.
 // Thoroughly tests data generated by modification of server-unknown item.
-TEST_F(ClientTagBasedModelTypeProcessorTest, LocalUpdateItem) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldCommitLocalUpdate) {
   InitializeToReadyState();
 
   bridge()->WriteItem(kKey1, kValue1);
-  EXPECT_EQ(1U, db().metadata_count());
+  ASSERT_EQ(1U, db().metadata_count());
   worker()->VerifyPendingCommits({{kHash1}});
 
   const CommitRequestData& request_data_v1 =
@@ -827,7 +830,7 @@
 
 // Tests that a local update that doesn't change specifics doesn't generate a
 // commit request.
-TEST_F(ClientTagBasedModelTypeProcessorTest, LocalUpdateItemRedundant) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldIgnoreRedundantLocalUpdate) {
   InitializeToReadyState();
   bridge()->WriteItem(kKey1, kValue1);
   EXPECT_EQ(1U, db().metadata_count());
@@ -838,7 +841,7 @@
 }
 
 // Thoroughly tests the data generated by a server item creation.
-TEST_F(ClientTagBasedModelTypeProcessorTest, ServerCreateItem) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldProcessRemoteCreation) {
   InitializeToReadyState();
   worker()->UpdateFromServer(kHash1, GenerateSpecifics(kKey1, kValue1));
   EXPECT_EQ(1U, db().data_count());
@@ -867,7 +870,8 @@
   EXPECT_TRUE(metadata.has_specifics_hash());
 }
 
-TEST_F(ClientTagBasedModelTypeProcessorTest, IgnoreUpdatesForRootNodes) {
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldIgnoreRemoteUpdatesForRootNodes) {
   InitializeToReadyState();
   UpdateResponseDataList update;
   update.push_back(worker()->GenerateTypeRootUpdateData(ModelType::SESSIONS));
@@ -879,7 +883,7 @@
 
 // Test that an error applying changes from a server update is
 // propagated to the error handler.
-TEST_F(ClientTagBasedModelTypeProcessorTest, ErrorApplyingUpdate) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldReportErrorApplyingUpdate) {
   InitializeToReadyState();
   bridge()->ErrorOnNextCall();
   ExpectError();
@@ -887,7 +891,7 @@
 }
 
 // Thoroughly tests the data generated by a server item creation.
-TEST_F(ClientTagBasedModelTypeProcessorTest, ServerUpdateItem) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldProcessRemoteUpdate) {
   InitializeToReadyState();
 
   // Local add writes data and metadata; ack writes metadata again.
@@ -908,7 +912,7 @@
 }
 
 // Tests locally deleting an acknowledged item.
-TEST_F(ClientTagBasedModelTypeProcessorTest, LocalDeleteItem) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldCommitLocalDeletion) {
   InitializeToReadyState();
   WriteItemAndAck(kKey1, kValue1);
   EXPECT_EQ(0U, worker()->GetNumPendingCommits());
@@ -947,7 +951,8 @@
 }
 
 // Tests that item created and deleted before sync cycle doesn't get committed.
-TEST_F(ClientTagBasedModelTypeProcessorTest, LocalDeleteItemUncommitted) {
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldNotCommitLocalDeletionOfUncommittedEntity) {
   InitializeToMetadataLoaded();
   bridge()->WriteItem(kKey1, kValue1);
   bridge()->DeleteItem(kKey1);
@@ -958,7 +963,8 @@
 
 // Tests creating and deleting an item locally before receiving a commit
 // response, then getting the commit responses.
-TEST_F(ClientTagBasedModelTypeProcessorTest, LocalDeleteItemInterleaved) {
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldHandleLocalDeletionDuringLocalCreationCommit) {
   InitializeToReadyState();
   bridge()->WriteItem(kKey1, kValue1);
   worker()->VerifyPendingCommits({{kHash1}});
@@ -1008,7 +1014,7 @@
   EXPECT_EQ(0U, ProcessorEntityCount());
 }
 
-TEST_F(ClientTagBasedModelTypeProcessorTest, ServerDeleteItem) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldProcessRemoteDeletion) {
   InitializeToReadyState();
   WriteItemAndAck(kKey1, kValue1);
   EXPECT_EQ(1U, ProcessorEntityCount());
@@ -1034,7 +1040,8 @@
 
 // Deletes an item we've never seen before.
 // Should have no effect and not crash.
-TEST_F(ClientTagBasedModelTypeProcessorTest, LocalDeleteUnknown) {
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldIgnoreLocalDeletionOfUnknownEntity) {
   InitializeToReadyState();
   bridge()->DeleteItem(kKey1);
   EXPECT_EQ(0U, db().data_count());
@@ -1045,7 +1052,8 @@
 
 // Deletes an item we've never seen before.
 // Should have no effect and not crash.
-TEST_F(ClientTagBasedModelTypeProcessorTest, ServerDeleteUnknown) {
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldIgnoreRemoteDeletionOfUnknownEntity) {
   InitializeToReadyState();
   worker()->TombstoneFromServer(kHash1);
   EXPECT_EQ(0U, db().data_count());
@@ -1056,7 +1064,8 @@
 
 // Tests that after committing entity fails, processor includes this entity in
 // consecutive commits.
-TEST_F(ClientTagBasedModelTypeProcessorTest, CommitFailedOnServer) {
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldRetryCommitAfterServerError) {
   InitializeToReadyState();
   bridge()->WriteItem(kKey1, kValue1);
   worker()->VerifyPendingCommits({{kHash1}});
@@ -1077,7 +1086,8 @@
 }
 
 // Tests that GetLocalChanges honors max_entries parameter.
-TEST_F(ClientTagBasedModelTypeProcessorTest, LocalChangesPagination) {
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldTruncateLocalChangesToMaxSize) {
   InitializeToMetadataLoaded();
   bridge()->WriteItem(kKey1, kValue1);
   bridge()->WriteItem(kKey2, kValue2);
@@ -1091,7 +1101,7 @@
 
 // Creates two different sync items.
 // Verifies that the second has no effect on the first.
-TEST_F(ClientTagBasedModelTypeProcessorTest, TwoIndependentItems) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldHandleTwoIndependentItems) {
   InitializeToReadyState();
   EXPECT_EQ(0U, worker()->GetNumPendingCommits());
 
@@ -1122,7 +1132,8 @@
   EXPECT_EQ(kUncommittedVersion, metadata2.server_version());
 }
 
-TEST_F(ClientTagBasedModelTypeProcessorTest, ConflictResolutionChangesMatch) {
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldNotTreatMatchingChangesAsConflict) {
   InitializeToReadyState();
   EntitySpecifics specifics = bridge()->WriteItem(kKey1, kValue1);
   EXPECT_EQ(1U, db().data_change_count());
@@ -1141,7 +1152,8 @@
   worker()->VerifyPendingCommits({{kHash1}});
 }
 
-TEST_F(ClientTagBasedModelTypeProcessorTest, ConflictResolutionUseLocal) {
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldResolveConflictToLocalVersion) {
   InitializeToReadyState();
   // WriteAndAck entity to get id from the server.
   WriteItemAndAck(kKey1, kValue1);
@@ -1160,7 +1172,8 @@
   worker()->VerifyNthPendingCommit(1, {kHash1}, {specifics2});
 }
 
-TEST_F(ClientTagBasedModelTypeProcessorTest, ConflictResolutionUseRemote) {
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldResolveConflictToRemoteVersion) {
   InitializeToReadyState();
   bridge()->WriteItem(kKey1, kValue1);
   bridge()->SetConflictResolution(ConflictResolution::UseRemote());
@@ -1174,7 +1187,8 @@
   worker()->VerifyPendingCommits({{kHash1}});
 }
 
-TEST_F(ClientTagBasedModelTypeProcessorTest, ConflictResolutionUseNew) {
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldResolveConflictToNewVersion) {
   InitializeToReadyState();
   bridge()->WriteItem(kKey1, kValue1);
   bridge()->SetConflictResolution(
@@ -1194,7 +1208,7 @@
 //
 // Creates items in various states of commit and verifies they re-attempt to
 // commit on reconnect.
-TEST_F(ClientTagBasedModelTypeProcessorTest, Disconnect) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldDisconnectAndReconnect) {
   InitializeToReadyState();
 
   // The first item is fully committed.
@@ -1229,7 +1243,7 @@
 //
 // Creates items in various states of commit and verifies they do NOT attempt to
 // commit on re-enable.
-TEST_F(ClientTagBasedModelTypeProcessorTest, Stop) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldStopAndKeepMetadata) {
   InitializeToReadyState();
 
   // The first item is fully committed.
@@ -1257,7 +1271,7 @@
 //
 // Creates items in various states of commit and verifies they re-attempt to
 // commit on re-enable.
-TEST_F(ClientTagBasedModelTypeProcessorTest, StopAndClearMetadata) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldStopAndClearMetadata) {
   InitializeToReadyState();
 
   // The first item is fully committed.
@@ -1284,7 +1298,7 @@
 }
 
 // Test re-encrypt everything when desired encryption key changes.
-TEST_F(ClientTagBasedModelTypeProcessorTest, ReEncryptCommitsWithNewKey) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldReencryptCommitsWithNewKey) {
   InitializeToReadyState();
 
   // Commit an item.
@@ -1312,7 +1326,8 @@
 
 // Test that an error loading pending commit data for re-encryption is
 // propagated to the error handler.
-TEST_F(ClientTagBasedModelTypeProcessorTest, ReEncryptErrorLoadingData) {
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldHandleErrorWhileReencrypting) {
   InitializeToReadyState();
   WriteItemAndAck(kKey1, kValue1);
   bridge()->ErrorOnNextCall();
@@ -1321,7 +1336,7 @@
 }
 
 // Test receipt of updates with new and old keys.
-TEST_F(ClientTagBasedModelTypeProcessorTest, ReEncryptUpdatesWithNewKey) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldReencryptUpdatesWithNewKey) {
   InitializeToReadyState();
 
   // Receive an unencrypted update.
@@ -1358,7 +1373,7 @@
 
 // Test that re-encrypting enqueues the right data for USE_LOCAL conflicts.
 TEST_F(ClientTagBasedModelTypeProcessorTest,
-       ReEncryptConflictResolutionUseLocal) {
+       ShouldResolveConflictToLocalDuringReencryption) {
   InitializeToReadyState();
   // WriteAndAck entity to get id from the server.
   WriteItemAndAck(kKey1, kValue1);
@@ -1385,7 +1400,7 @@
 
 // Test that re-encrypting enqueues the right data for USE_REMOTE conflicts.
 TEST_F(ClientTagBasedModelTypeProcessorTest,
-       ReEncryptConflictResolutionUseRemote) {
+       ShouldResolveConflictToRemoteDuringReencryption) {
   InitializeToReadyState();
   worker()->UpdateWithEncryptionKey("k1");
   bridge()->WriteItem(kKey1, kValue1);
@@ -1403,7 +1418,7 @@
 
 // Test that re-encrypting enqueues the right data for USE_NEW conflicts.
 TEST_F(ClientTagBasedModelTypeProcessorTest,
-       ReEncryptConflictResolutionUseNew) {
+       ShouldResolveConflictToNewDuringReencryption) {
   InitializeToReadyState();
   worker()->UpdateWithEncryptionKey("k1");
   bridge()->WriteItem(kKey1, kValue1);
@@ -1420,7 +1435,8 @@
   EXPECT_EQ(kValue3, db().GetValue(kKey1));
 }
 
-TEST_F(ClientTagBasedModelTypeProcessorTest, ReEncryptConflictWhileLoading) {
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldHandleConflictWhileLoadingForReencryption) {
   InitializeToReadyState();
   // Create item and ack so its data is no longer cached.
   WriteItemAndAck(kKey1, kValue1);
@@ -1444,7 +1460,8 @@
 }
 
 // Tests that a real remote change wins over a local encryption-only change.
-TEST_F(ClientTagBasedModelTypeProcessorTest, IgnoreLocalEncryption) {
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldIgnoreLocalEncryptionChange) {
   InitializeToReadyState();
   EntitySpecifics specifics = WriteItemAndAck(kKey1, kValue1);
   worker()->UpdateWithEncryptionKey("k1");
@@ -1457,7 +1474,8 @@
 }
 
 // Tests that updates without client tags get dropped.
-TEST_F(ClientTagBasedModelTypeProcessorTest, DropsClientTags) {
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldDropRemoteUpdatesWithoutClientTags) {
   InitializeToReadyState();
   UpdateResponseDataList updates;
   updates.push_back(worker()->GenerateUpdateData(
@@ -1481,7 +1499,7 @@
 // TODO(crbug.com/874001): Remove this feature-specific logic when the right
 // solution for Wallet data has been decided.
 TEST_F(WalletDataClientTagBasedModelTypeProcessorTest,
-       CreatesClientTagsForWallet) {
+       ShouldCreateClientTagsForWallet) {
   InitializeToReadyState();
 
   // Commit an item.
@@ -1497,7 +1515,7 @@
 }
 
 // Tests that a real local change wins over a remote encryption-only change.
-TEST_F(ClientTagBasedModelTypeProcessorTest, IgnoreRemoteEncryption) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldIgnoreRemoteEncryption) {
   InitializeToReadyState();
   EntitySpecifics specifics1 = WriteItemAndAck(kKey1, kValue1);
 
@@ -1512,7 +1530,7 @@
 
 // Same as above but with two commit requests before one ack.
 TEST_F(ClientTagBasedModelTypeProcessorTest,
-       IgnoreRemoteEncryptionInterleaved) {
+       ShouldIgnoreRemoteEncryptionInterleaved) {
   InitializeToReadyState();
   // WriteAndAck entity to get id from the server.
   WriteItemAndAck(kKey1, kValue1);
@@ -1535,7 +1553,7 @@
 // and updates corresponding entity's metadata in MetadataChangeList, and
 // UntrackEntity will remove corresponding ProcessorEntityTracker and do not add
 // any entity's metadata into MetadataChangeList.
-TEST_F(ClientTagBasedModelTypeProcessorTest, UpdateStorageKey) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldUpdateStorageKey) {
   // Setup bridge to not support calls to GetStorageKey. This will cause
   // FakeModelTypeSyncBridge to call UpdateStorageKey for new entities and will
   // DCHECK if GetStorageKey gets called.
@@ -1579,7 +1597,8 @@
 // GetStorageKey(). When update from server delivers updated encryption key, all
 // entities should be reencrypted including new entity that just got received
 // from server.
-TEST_F(ClientTagBasedModelTypeProcessorTest, ReencryptionWithEmptyStorageKeys) {
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldReencryptDatatypeWithoutStorageKeySupport) {
   bridge()->SetSupportsGetStorageKey(false);
   InitializeToReadyState();
 
@@ -1593,7 +1612,7 @@
 // Tests that UntrackEntity won't propagate storage key to
 // ProcessorEntityTracker, and no entity's metadata are added into
 // MetadataChangeList.
-TEST_F(ClientTagBasedModelTypeProcessorTest, UntrackEntity) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldUntrackEntity) {
   // Setup bridge to not support calls to GetStorageKey. This will cause
   // FakeModelTypeSyncBridge to call UpdateStorageKey for new entities and will
   // DCHECK if GetStorageKey gets called.
@@ -1617,7 +1636,7 @@
 // Tests that UntrackEntityForStorage won't propagate storage key to
 // ProcessorEntityTracker, and no entity's metadata are added into
 // MetadataChangeList.
-TEST_F(ClientTagBasedModelTypeProcessorTest, UntrackEntityForStorageKey) {
+TEST_F(ClientTagBasedModelTypeProcessorTest, ShouldUntrackEntityForStorageKey) {
   InitializeToReadyState();
   bridge()->WriteItem(kKey1, kValue1);
   worker()->VerifyPendingCommits({{kHash1}});
@@ -1646,7 +1665,7 @@
 // Tests that UntrackEntityForStorage does not crash if no such entity is being
 // tracked.
 TEST_F(ClientTagBasedModelTypeProcessorTest,
-       UntrackEntityForStorageKeyNonexistent) {
+       ShouldIgnoreUntrackEntityForInexistentStorageKey) {
   InitializeToReadyState();
 
   // This should not crash for an unknown storage key and simply ignore the
@@ -1674,7 +1693,7 @@
 // Garbage collection by version is used by the server to replace all data on
 // the client, and is implemented by calling MergeSyncData on the bridge.
 TEST_F(FullUpdateClientTagBasedModelTypeProcessorTest,
-       GarbageCollectionByVersionFullUpdate) {
+       ShouldApplyGarbageCollectionByVersionFullUpdate) {
   InitializeToReadyState();
   UpdateResponseDataList updates;
   updates.push_back(worker()->GenerateUpdateData(
@@ -1711,7 +1730,7 @@
 // Tests that the processor reports an error for updates without a version GC
 // directive that are received for types that don't support incremental updates.
 TEST_F(FullUpdateClientTagBasedModelTypeProcessorTest,
-       UpdateWithoutVersionForFullUpdateBridge) {
+       ShouldReportErrorForUnsupportedIncrementalUpdate) {
   InitializeToReadyState();
 
   ExpectError();
@@ -1721,7 +1740,7 @@
 // Tests that empty updates without a version GC are ignored for types that
 // don't support incremental updates.
 TEST_F(FullUpdateClientTagBasedModelTypeProcessorTest,
-       EmptyUpdateForFullUpdateBridge) {
+       ShouldIgnoreEmptyUpdate) {
   InitializeToReadyState();
 
   worker()->UpdateFromServer(UpdateResponseDataList());
@@ -1734,7 +1753,7 @@
 // Tests that the processor correctly handles an initial (non-empty) update
 // without any gc directives (as it happens in the migration to USS).
 TEST_F(FullUpdateClientTagBasedModelTypeProcessorTest,
-       InitialUpdateForFullUpdateBridge) {
+       ShouldProcessInitialUpdate) {
   // Do not set any model type state to emulate that initial sync has not been
   // done yet.
   ModelReadyToSync();
@@ -1746,7 +1765,7 @@
 // Tests that the processor reports an error for updates with a version GC
 // directive that are received for types that support incremental updates.
 TEST_F(ClientTagBasedModelTypeProcessorTest,
-       GarbageCollectionByVersionForIncrementalUpdateBridge) {
+       ShouldApplyGarbageCollectionByVersion) {
   InitializeToReadyState();
 
   ExpectError();
@@ -1758,7 +1777,8 @@
 // Tests that ClientTagBasedModelTypeProcessor can do garbage collection by age.
 // Create 2 entries, one is 15-days-old, another is 5-days-old. Check if sync
 // will delete 15-days-old entry when server set expired age is 10 days.
-TEST_F(ClientTagBasedModelTypeProcessorTest, GarbageCollectionByAge) {
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldApplyGarbageCollectionByAge) {
   InitializeToReadyState();
 
   // Create 2 entries, one is 15-days-old, another is 5-days-old.
@@ -1793,7 +1813,8 @@
 // limit. Create 3 entries, one is 15-days-old, one is 10-days-old, another is
 // 5-days-old. Check if sync will delete 15-days-old entry when server set
 // limited item is 2 days.
-TEST_F(ClientTagBasedModelTypeProcessorTest, GarbageCollectionByItemLimit) {
+TEST_F(ClientTagBasedModelTypeProcessorTest,
+       ShouldApplyGarbageCollectionByItemLimit) {
   InitializeToReadyState();
 
   // Create 3 entries, one is 15-days-old, one is 10-days-old, another is
@@ -1860,7 +1881,8 @@
 };
 
 // Test that commit only types are deleted after commit response.
-TEST_F(CommitOnlyClientTagBasedModelTypeProcessorTest, Simple) {
+TEST_F(CommitOnlyClientTagBasedModelTypeProcessorTest,
+       ShouldCommitAndDeleteWhenAcked) {
   InitializeToReadyState();
   EXPECT_TRUE(db().model_type_state().initial_sync_done());
 
@@ -1876,7 +1898,8 @@
 
 // Test that commit only types maintain tracking of entities while unsynced
 // changes exist.
-TEST_F(CommitOnlyClientTagBasedModelTypeProcessorTest, UnsyncedChanges) {
+TEST_F(CommitOnlyClientTagBasedModelTypeProcessorTest,
+       ShouldTrackUnsyncedChangesAfterPartialCommit) {
   InitializeToReadyState();
 
   bridge()->WriteItem(kKey1, kValue1);
diff --git a/components/translate/core/browser/translate_manager_unittest.cc b/components/translate/core/browser/translate_manager_unittest.cc
index 8047526..804cd44 100644
--- a/components/translate/core/browser/translate_manager_unittest.cc
+++ b/components/translate/core/browser/translate_manager_unittest.cc
@@ -491,6 +491,13 @@
   EXPECT_THAT(histogram_tester.GetAllSamples(kInitiationStatusName),
               ElementsAre(Bucket(INITIATION_STATUS_SHOW_INFOBAR, 2),
                           Bucket(INITIATION_STATUS_SHOW_ICON, 2)));
+
+  // Initiating Translation again should still show the UI because accepting
+  // once prevents backoff from occurring moving forward.
+  translate_manager_->InitiateTranslation("en");
+  EXPECT_THAT(histogram_tester.GetAllSamples(kInitiationStatusName),
+              ElementsAre(Bucket(INITIATION_STATUS_SHOW_INFOBAR, 3),
+                          Bucket(INITIATION_STATUS_SHOW_ICON, 3)));
 }
 
 TEST_F(TranslateManagerTest, ShouldHonorExperimentRankerEnforcement_Enforce) {
diff --git a/components/translate/core/browser/translate_prefs.cc b/components/translate/core/browser/translate_prefs.cc
index 1fa453d4..e61022f 100644
--- a/components/translate/core/browser/translate_prefs.cc
+++ b/components/translate/core/browser/translate_prefs.cc
@@ -60,6 +60,8 @@
     "translate_auto_always_count";
 const char TranslatePrefs::kPrefTranslateAutoNeverCount[] =
     "translate_auto_never_count";
+const char TranslatePrefs::kPrefExplicitLanguageAskShown[] =
+    "translate_explicit_language_ask_shown";
 #endif
 
 // The below properties used to be used but now are deprecated. Don't use them
@@ -718,6 +720,14 @@
   DictionaryPrefUpdate update(prefs_, kPrefTranslateAutoNeverCount);
   update.Get()->SetInteger(language, 0);
 }
+
+bool TranslatePrefs::GetExplicitLanguageAskPromptShown() const {
+  return prefs_->GetBoolean(kPrefExplicitLanguageAskShown);
+}
+
+void TranslatePrefs::SetExplicitLanguageAskPromptShown(bool shown) {
+  prefs_->SetBoolean(kPrefExplicitLanguageAskShown, shown);
+}
 #endif  // defined(OS_ANDROID)
 
 void TranslatePrefs::UpdateLastDeniedTime(const std::string& language) {
@@ -829,13 +839,14 @@
 
 void TranslatePrefs::ReportForceTriggerOnEnglishPages() {
   int current_count = GetForceTriggerOnEnglishPagesCount();
-  prefs_->SetInteger(kForceTriggerTranslateCount, current_count + 1);
+  if (current_count != -1)
+    prefs_->SetInteger(kForceTriggerTranslateCount, current_count + 1);
 }
 
 void TranslatePrefs::ReportAcceptedAfterForceTriggerOnEnglishPages() {
   int current_count = GetForceTriggerOnEnglishPagesCount();
-  if (current_count > 0)
-    prefs_->SetInteger(kForceTriggerTranslateCount, current_count - 1);
+  if (current_count != -1)
+    prefs_->SetInteger(kForceTriggerTranslateCount, -1);
 }
 
 // static
@@ -877,6 +888,9 @@
   registry->RegisterDictionaryPref(
       kPrefTranslateAutoNeverCount,
       user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
+  registry->RegisterBooleanPref(
+      kPrefExplicitLanguageAskShown, false,
+      user_prefs::PrefRegistrySyncable::SYNCABLE_PREF);
 #endif
 }
 
diff --git a/components/translate/core/browser/translate_prefs.h b/components/translate/core/browser/translate_prefs.h
index de15f3fc..a67e53c 100644
--- a/components/translate/core/browser/translate_prefs.h
+++ b/components/translate/core/browser/translate_prefs.h
@@ -139,6 +139,7 @@
 #if defined(OS_ANDROID)
   static const char kPrefTranslateAutoAlwaysCount[];
   static const char kPrefTranslateAutoNeverCount[];
+  static const char kPrefExplicitLanguageAskShown[];
 #endif
 
   // This parameter specifies how the language should be moved within the list.
@@ -268,6 +269,11 @@
   int GetTranslationAutoNeverCount(const std::string& language) const;
   void IncrementTranslationAutoNeverCount(const std::string& language);
   void ResetTranslationAutoNeverCount(const std::string& language);
+
+  // These methods are used to determine whether the explicit language ask
+  // prompt was displayed to the user already.
+  bool GetExplicitLanguageAskPromptShown() const;
+  void SetExplicitLanguageAskPromptShown(bool shown);
 #endif
 
   // Update the last time on closing the Translate UI without translation.
@@ -301,9 +307,10 @@
   // kOverrideTranslateTriggerInIndia experiment made translate trigger on an
   // English page when it otherwise wouldn't have.
   void ReportForceTriggerOnEnglishPages();
-  // Decrements the pref that represents how often the
+  // Sets to -1 the pref that represents how often the
   // kOverrideTranslateTriggerInIndia experiment made translate trigger on an
-  // English page when it otherwise wouldn't have.
+  // English page when it otherwise wouldn't have. This is a special value that
+  // signals that the backoff should not happen for that user.
   void ReportAcceptedAfterForceTriggerOnEnglishPages();
 
   // Migrate the sites blacklist from a list to a dictionary that maps sites
diff --git a/components/viz/host/DEPS b/components/viz/host/DEPS
index 036d1f1f..da78f96 100644
--- a/components/viz/host/DEPS
+++ b/components/viz/host/DEPS
@@ -20,6 +20,7 @@
   "+skia",
   "+third_party/skia",
   "+ui/accelerated_widget_mac",
+  "+ui/ozone/public",
 ]
 
 specific_include_rules = {
diff --git a/components/viz/host/gpu_host_impl.cc b/components/viz/host/gpu_host_impl.cc
index 5d14b53c..3b9b27a 100644
--- a/components/viz/host/gpu_host_impl.cc
+++ b/components/viz/host/gpu_host_impl.cc
@@ -12,6 +12,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/no_destructor.h"
 #include "base/threading/thread_checker.h"
+#include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
 #include "components/viz/common/features.h"
@@ -22,7 +23,10 @@
 #include "gpu/ipc/common/gpu_client_ids.h"
 #include "gpu/ipc/host/shader_disk_cache.h"
 #include "ipc/ipc_channel.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/gfx/font_render_params.h"
+#include "ui/ozone/public/gpu_platform_support_host.h"
+#include "ui/ozone/public/ozone_platform.h"
 
 #if defined(OS_ANDROID)
 #include "base/android/build_info.h"
@@ -75,6 +79,30 @@
   return *instance;
 }
 
+#if defined(USE_OZONE)
+// Helper to register Mus/conventional thread bouncers for ozone startup.
+void OzoneRegisterStartupCallbackHelper(
+    scoped_refptr<base::SingleThreadTaskRunner> host_thread_task_runner,
+    base::OnceCallback<void(ui::OzonePlatform*)> callback) {
+  // The callback registered in ozone can be called in any thread. So use an
+  // intermediary callback that bounces to the GpuHost thread if needed, before
+  // running the callback.
+  auto bounce_callback = base::BindOnce(
+      [](base::SingleThreadTaskRunner* host_thread_task_runner,
+         base::OnceCallback<void(ui::OzonePlatform*)> callback,
+         ui::OzonePlatform* platform) {
+        if (host_thread_task_runner->BelongsToCurrentThread()) {
+          std::move(callback).Run(platform);
+        } else {
+          host_thread_task_runner->PostTask(
+              FROM_HERE, base::BindOnce(std::move(callback), platform));
+        }
+      },
+      base::RetainedRef(host_thread_task_runner), std::move(callback));
+  ui::OzonePlatform::RegisterStartupCallback(std::move(bounce_callback));
+}
+#endif  // defined(USE_OZONE)
+
 }  // namespace
 
 GpuHostImpl::InitParams::InitParams() = default;
@@ -89,6 +117,7 @@
     : delegate_(delegate),
       channel_(channel),
       params_(std::move(params)),
+      host_thread_task_runner_(base::ThreadTaskRunnerHandle::Get()),
       gpu_host_binding_(this),
       weak_ptr_factory_(this) {
   DCHECK(delegate_);
@@ -108,6 +137,10 @@
       mojo::MakeRequest(&gpu_service_ptr_), std::move(host_proxy),
       std::move(discardable_manager_ptr), activity_flags_.CloneHandle(),
       GetFontRenderParams().Get()->subpixel_rendering);
+
+#if defined(USE_OZONE)
+  InitOzone();
+#endif  // defined(USE_OZONE)
 }
 
 GpuHostImpl::~GpuHostImpl() = default;
@@ -242,12 +275,87 @@
   }
 }
 
+void GpuHostImpl::BindInterface(const std::string& interface_name,
+                                mojo::ScopedMessagePipeHandle interface_pipe) {
+  delegate_->BindInterface(interface_name, std::move(interface_pipe));
+}
+
 mojom::GpuService* GpuHostImpl::gpu_service() {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   DCHECK(gpu_service_ptr_.is_bound());
   return gpu_service_ptr_.get();
 }
 
+#if defined(USE_OZONE)
+void GpuHostImpl::InitOzone() {
+  // Ozone needs to send the primary DRM device to GPU service as early as
+  // possible to ensure the latter always has a valid device.
+  // https://crbug.com/608839
+  // If the OzonePlatform is not created yet, defer the callback until
+  // OzonePlatform instance is created.
+  bool using_mojo = true;
+#if defined(OS_CHROMEOS)
+  using_mojo = features::IsOzoneDrmMojo();
+#endif
+  if (using_mojo) {
+    // TODO(rjkroege): Remove the legacy IPC code paths when no longer
+    // necessary. https://crbug.com/806092
+    auto interface_binder = base::BindRepeating(&GpuHostImpl::BindInterface,
+                                                weak_ptr_factory_.GetWeakPtr());
+    auto terminate_callback = base::BindOnce(&GpuHostImpl::TerminateGpuProcess,
+                                             weak_ptr_factory_.GetWeakPtr());
+
+    auto startup_callback = base::BindOnce(
+        [](const base::RepeatingCallback<void(const std::string&,
+                                              mojo::ScopedMessagePipeHandle)>&
+               interface_binder,
+           base::OnceCallback<void(const std::string&)> terminate_callback,
+           scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner,
+           scoped_refptr<base::SingleThreadTaskRunner> host_thread_task_runner,
+           ui::OzonePlatform* platform) {
+          DCHECK(host_thread_task_runner->BelongsToCurrentThread());
+          platform->GetGpuPlatformSupportHost()->OnGpuServiceLaunched(
+              main_thread_task_runner, host_thread_task_runner,
+              interface_binder, std::move(terminate_callback));
+        },
+        interface_binder, std::move(terminate_callback),
+        params_.main_thread_task_runner, host_thread_task_runner_);
+    OzoneRegisterStartupCallbackHelper(host_thread_task_runner_,
+                                       std::move(startup_callback));
+  } else {
+    auto send_callback = base::BindRepeating(
+        [](base::WeakPtr<GpuHostImpl> host, IPC::Message* message) {
+          if (host)
+            host->delegate_->SendGpuProcessMessage(message);
+          else
+            delete message;
+        },
+        weak_ptr_factory_.GetWeakPtr());
+    // Create the callback that should run on the current thread.
+    auto startup_callback = base::BindOnce(
+        [](int host_id,
+           const base::RepeatingCallback<void(IPC::Message*)>& send_callback,
+           scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner,
+           scoped_refptr<base::SingleThreadTaskRunner> host_thread_task_runner,
+           ui::OzonePlatform* platform) {
+          DCHECK(host_thread_task_runner->BelongsToCurrentThread());
+          platform->GetGpuPlatformSupportHost()->OnGpuProcessLaunched(
+              host_id, main_thread_task_runner, host_thread_task_runner,
+              send_callback);
+        },
+        params_.restart_id, send_callback, params_.main_thread_task_runner,
+        host_thread_task_runner_);
+    OzoneRegisterStartupCallbackHelper(host_thread_task_runner_,
+                                       std::move(startup_callback));
+  }
+}
+
+void GpuHostImpl::TerminateGpuProcess(const std::string& message) {
+  delegate_->TerminateGpuProcess(message);
+}
+
+#endif  // defined(USE_OZONE)
+
 std::string GpuHostImpl::GetShaderPrefixKey() {
   if (shader_prefix_key_.empty()) {
     const gpu::GPUInfo& info = delegate_->GetGPUInfo();
diff --git a/components/viz/host/gpu_host_impl.h b/components/viz/host/gpu_host_impl.h
index 64c7474..c96d6bdf 100644
--- a/components/viz/host/gpu_host_impl.h
+++ b/components/viz/host/gpu_host_impl.h
@@ -78,6 +78,16 @@
     virtual void BindDiscardableMemoryRequest(
         discardable_memory::mojom::DiscardableSharedMemoryManagerRequest
             request) = 0;
+    virtual void BindInterface(
+        const std::string& interface_name,
+        mojo::ScopedMessagePipeHandle interface_pipe) = 0;
+#if defined(USE_OZONE)
+    virtual void TerminateGpuProcess(const std::string& message) = 0;
+
+    // TODO(https://crbug.com/806092): Remove this when legacy IPC-based Ozone
+    // is removed.
+    virtual void SendGpuProcessMessage(IPC::Message* message) = 0;
+#endif
 
    protected:
     virtual ~Delegate() {}
@@ -103,6 +113,9 @@
 
     // Number of frames to CompositorFrame activation deadline.
     base::Optional<uint32_t> deadline_to_synchronize_surfaces = base::nullopt;
+
+    // Task runner corresponding to the main thread.
+    scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner;
   };
 
   enum class EstablishChannelStatus {
@@ -146,6 +159,9 @@
 
   void SendOutstandingReplies();
 
+  void BindInterface(const std::string& interface_name,
+                     mojo::ScopedMessagePipeHandle interface_pipe);
+
   mojom::GpuService* gpu_service();
 
   bool initialized() const { return initialized_; }
@@ -155,6 +171,11 @@
   }
 
  private:
+#if defined(USE_OZONE)
+  void InitOzone();
+  void TerminateGpuProcess(const std::string& message);
+#endif  // defined(USE_OZONE)
+
   std::string GetShaderPrefixKey();
 
   void LoadedShader(int32_t client_id,
@@ -195,6 +216,9 @@
   IPC::Channel* const channel_;
   const InitParams params_;
 
+  // Task runner corresponding to the thread |this| is created on.
+  scoped_refptr<base::SingleThreadTaskRunner> host_thread_task_runner_;
+
   mojom::VizMainAssociatedPtr viz_main_ptr_;
   mojom::GpuServicePtr gpu_service_ptr_;
   mojo::Binding<mojom::GpuHost> gpu_host_binding_;
diff --git a/components/wifi/BUILD.gn b/components/wifi/BUILD.gn
index 3cd5593..7dedbf03 100644
--- a/components/wifi/BUILD.gn
+++ b/components/wifi/BUILD.gn
@@ -2,7 +2,9 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-component("wifi") {
+import("//build/config/jumbo.gni")
+
+jumbo_component("wifi") {
   sources = [
     "network_properties.cc",
     "network_properties.h",
@@ -35,7 +37,7 @@
   }
 }
 
-static_library("test_support") {
+jumbo_static_library("test_support") {
   sources = [
     "fake_wifi_service.cc",
     "fake_wifi_service.h",
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index 82d691a..fd424a6 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -887,6 +887,7 @@
     "gpu/browser_gpu_client_delegate.h",
     "gpu/compositor_util.cc",
     "gpu/compositor_util.h",
+    "gpu/delegate_to_browser_gpu_service_accelerator_factory.cc",
     "gpu/gpu_client.cc",
     "gpu/gpu_data_manager_impl.cc",
     "gpu/gpu_data_manager_impl.h",
@@ -904,6 +905,8 @@
     "gpu/gpu_process_host.h",
     "gpu/shader_cache_factory.cc",
     "gpu/shader_cache_factory.h",
+    "gpu/video_capture_dependencies.cc",
+    "gpu/video_capture_dependencies.h",
     "histogram_controller.cc",
     "histogram_controller.h",
     "histogram_subscriber.h",
@@ -1446,8 +1449,6 @@
     "renderer_host/media/video_capture_controller.cc",
     "renderer_host/media/video_capture_controller.h",
     "renderer_host/media/video_capture_controller_event_handler.h",
-    "renderer_host/media/video_capture_dependencies.cc",
-    "renderer_host/media/video_capture_dependencies.h",
     "renderer_host/media/video_capture_device_launch_observer.h",
     "renderer_host/media/video_capture_factory_delegate.cc",
     "renderer_host/media/video_capture_factory_delegate.h",
diff --git a/content/browser/android/app_web_message_port.cc b/content/browser/android/app_web_message_port.cc
index ec7b9ba..ac0b990 100644
--- a/content/browser/android/app_web_message_port.cc
+++ b/content/browser/android/app_web_message_port.cc
@@ -10,7 +10,7 @@
 #include "base/bind.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "jni/AppWebMessagePort_jni.h"
-#include "third_party/blink/public/common/message_port/string_message_codec.h"
+#include "third_party/blink/public/common/messaging/string_message_codec.h"
 
 using blink::MessagePortChannel;
 
diff --git a/content/browser/android/app_web_message_port.h b/content/browser/android/app_web_message_port.h
index 2dd9402..2d1f3a4 100644
--- a/content/browser/android/app_web_message_port.h
+++ b/content/browser/android/app_web_message_port.h
@@ -6,7 +6,7 @@
 #define CONTENT_BROWSER_ANDROID_APP_WEB_MESSAGE_PORT_H_
 
 #include "base/android/jni_weak_ref.h"
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
 
 namespace content {
 
diff --git a/content/browser/android/dialog_overlay_impl.cc b/content/browser/android/dialog_overlay_impl.cc
index 70457ba..3ccc1ac9 100644
--- a/content/browser/android/dialog_overlay_impl.cc
+++ b/content/browser/android/dialog_overlay_impl.cc
@@ -71,7 +71,8 @@
                                      bool power_efficient)
     : WebContentsObserver(web_contents),
       rfhi_(rfhi),
-      power_efficient_(power_efficient) {
+      power_efficient_(power_efficient),
+      observed_window_android_(false) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   DCHECK(rfhi_);
 
@@ -105,9 +106,11 @@
   // Send the initial token, if there is one.  The observer will notify us about
   // changes only.
   if (auto* window = web_contents()->GetNativeView()->GetWindowAndroid()) {
+    RegisterWindowObserverIfNeeded(window);
     ScopedJavaLocalRef<jobject> token = window->GetWindowToken();
-    if (!token.is_null())
+    if (!token.is_null()) {
       Java_DialogOverlayImpl_onWindowToken(env, obj, token);
+    }
     // else we will send one if we get a callback from ViewAndroid.
   }
 }
@@ -117,7 +120,7 @@
 }
 
 void DialogOverlayImpl::Stop() {
-  UnregisterForTokensIfNeeded();
+  UnregisterCallbacksIfNeeded();
 
   JNIEnv* env = AttachCurrentThread();
   ScopedJavaLocalRef<jobject> obj = obj_.get(env);
@@ -129,7 +132,7 @@
 
 void DialogOverlayImpl::Destroy(JNIEnv* env, const JavaParamRef<jobject>& obj) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  UnregisterForTokensIfNeeded();
+  UnregisterCallbacksIfNeeded();
   // We delete soon since this might be part of an onDismissed callback.
   BrowserThread::DeleteSoon(BrowserThread::UI, FROM_HERE, this);
 }
@@ -145,7 +148,7 @@
                                                  point.y());
 }
 
-void DialogOverlayImpl::UnregisterForTokensIfNeeded() {
+void DialogOverlayImpl::UnregisterCallbacksIfNeeded() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   if (!rfhi_)
@@ -158,6 +161,12 @@
   if (delegate)
     delegate->SetOverlayMode(false);
 
+  if (observed_window_android_) {
+    auto* window_android = web_contents()->GetNativeView()->GetWindowAndroid();
+    if (window_android)
+      window_android->RemoveObserver(this);
+    observed_window_android_ = false;
+  }
   web_contents()->GetNativeView()->RemoveObserver(this);
   rfhi_ = nullptr;
 }
@@ -187,6 +196,11 @@
     Stop();
 }
 
+void DialogOverlayImpl::OnRootWindowVisibilityChanged(bool visible) {
+  if (!visible)
+    Stop();
+}
+
 void DialogOverlayImpl::WebContentsDestroyed() {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   Stop();
@@ -213,9 +227,10 @@
 
   ScopedJavaLocalRef<jobject> token;
 
-  if (auto* window = web_contents()->GetNativeView()->GetWindowAndroid())
+  if (auto* window = web_contents()->GetNativeView()->GetWindowAndroid()) {
+    RegisterWindowObserverIfNeeded(window);
     token = window->GetWindowToken();
-
+  }
   ScopedJavaLocalRef<jobject> obj = obj_.get(env);
   if (!obj.is_null())
     Java_DialogOverlayImpl_onWindowToken(env, obj, token);
@@ -228,6 +243,14 @@
     Java_DialogOverlayImpl_onWindowToken(env, obj, nullptr);
 }
 
+void DialogOverlayImpl::RegisterWindowObserverIfNeeded(
+    ui::WindowAndroid* window) {
+  if (!observed_window_android_) {
+    observed_window_android_ = true;
+    window->AddObserver(this);
+  }
+}
+
 static jint JNI_DialogOverlayImpl_RegisterSurface(
     JNIEnv* env,
     const base::android::JavaParamRef<jclass>& jcaller,
diff --git a/content/browser/android/dialog_overlay_impl.h b/content/browser/android/dialog_overlay_impl.h
index 4cb4cbe..1e955a8 100644
--- a/content/browser/android/dialog_overlay_impl.h
+++ b/content/browser/android/dialog_overlay_impl.h
@@ -12,6 +12,8 @@
 #include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "ui/android/view_android_observer.h"
+#include "ui/android/window_android.h"
+#include "ui/android/window_android_observer.h"
 
 namespace content {
 
@@ -20,6 +22,7 @@
 // detached from a WindowAndroid, we get the Android window token and notify the
 // java side.
 class DialogOverlayImpl : public ui::ViewAndroidObserver,
+                          public ui::WindowAndroidObserver,
                           public WebContentsObserver {
  public:
   // This may not call back into |obj| directly, but must post.  This is because
@@ -59,12 +62,21 @@
   void RenderFrameHostChanged(RenderFrameHost* old_host,
                               RenderFrameHost* new_host) override;
 
-  // Unregister for tokens if we're registered.
-  void UnregisterForTokensIfNeeded();
+  // Unregister callbacks if previously registered.
+  void UnregisterCallbacksIfNeeded();
+
+  // WindowAndroidObserver
+  void OnRootWindowVisibilityChanged(bool visible) override;
+  void OnCompositingDidCommit() override {}
+  void OnAttachCompositor() override {}
+  void OnDetachCompositor() override {}
+  void OnActivityStopped() override {}
+  void OnActivityStarted() override {}
 
  private:
   // Signals the overlay should be cleaned up and no longer used.
   void Stop();
+  void RegisterWindowObserverIfNeeded(ui::WindowAndroid* window);
 
   // Java object that owns us.
   JavaObjectWeakGlobalRef obj_;
@@ -74,6 +86,9 @@
 
   // Do we care about power efficiency?
   bool power_efficient_;
+
+  // Whether we added ourselves as an observer through WindowAndroid.
+  bool observed_window_android_;
 };
 
 }  // namespace content
diff --git a/content/browser/frame_host/origin_policy_throttle.cc b/content/browser/frame_host/origin_policy_throttle.cc
index 5d2904a6..b444afa 100644
--- a/content/browser/frame_host/origin_policy_throttle.cc
+++ b/content/browser/frame_host/origin_policy_throttle.cc
@@ -37,7 +37,12 @@
     const GURL& url,
     std::string* request_version) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  if (!base::FeatureList::IsEnabled(features::kOriginPolicy))
+
+  bool origin_policy_enabled =
+      base::FeatureList::IsEnabled(features::kOriginPolicy) ||
+      base::CommandLine::ForCurrentProcess()->HasSwitch(
+          switches::kEnableExperimentalWebPlatformFeatures);
+  if (!origin_policy_enabled)
     return false;
 
   if (!url.SchemeIs(url::kHttpsScheme))
@@ -64,7 +69,11 @@
           net::HttpRequestHeaders::kSecOriginPolicy))
     return nullptr;
 
-  DCHECK(base::FeatureList::IsEnabled(features::kOriginPolicy));
+  // TODO(vogelheim): Rewrite & hoist up this DCHECK to ensure that ..HasHeader
+  //     and ShouldRequestOriginPolicy are always equal on entry to the method.
+  //     This depends on https://crbug.com/881234 being fixed.
+  DCHECK(OriginPolicyThrottle::ShouldRequestOriginPolicy(handle->GetURL(),
+                                                         nullptr));
   return base::WrapUnique(new OriginPolicyThrottle(handle));
 }
 
diff --git a/content/browser/gpu/delegate_to_browser_gpu_service_accelerator_factory.cc b/content/browser/gpu/delegate_to_browser_gpu_service_accelerator_factory.cc
new file mode 100644
index 0000000..1d37054
--- /dev/null
+++ b/content/browser/gpu/delegate_to_browser_gpu_service_accelerator_factory.cc
@@ -0,0 +1,16 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/public/browser/delegate_to_browser_gpu_service_accelerator_factory.h"
+
+#include "content/browser/gpu/video_capture_dependencies.h"
+
+namespace content {
+
+void DelegateToBrowserGpuServiceAcceleratorFactory::CreateJpegDecodeAccelerator(
+    media::mojom::JpegDecodeAcceleratorRequest jda_request) {
+  VideoCaptureDependencies::CreateJpegDecodeAccelerator(std::move(jda_request));
+}
+
+}  // namespace content
diff --git a/content/browser/gpu/gpu_process_host.cc b/content/browser/gpu/gpu_process_host.cc
index 756936a2..a135b69d 100644
--- a/content/browser/gpu/gpu_process_host.cc
+++ b/content/browser/gpu/gpu_process_host.cc
@@ -276,39 +276,6 @@
   callback.Run(host);
 }
 
-#if defined(USE_OZONE)
-// The ozone platform use this callback to send IPC messages to the gpu process.
-void SendGpuProcessMessage(base::WeakPtr<GpuProcessHost> host,
-                           IPC::Message* message) {
-  if (host)
-    host->Send(message);
-  else
-    delete message;
-}
-
-// Helper to register Mus/conventional thread bouncers for ozone startup.
-void OzoneRegisterStartupCallbackHelper(
-    base::OnceCallback<void(ui::OzonePlatform*)> io_callback) {
-  // The callback registered in ozone can be called in any thread. So use an
-  // intermediary callback that bounces to the IO thread if needed, before
-  // running the callback.
-  auto bounce_callback = base::BindOnce(
-      [](base::TaskRunner* task_runner,
-         base::OnceCallback<void(ui::OzonePlatform*)> callback,
-         ui::OzonePlatform* platform) {
-        if (task_runner->RunsTasksInCurrentSequence()) {
-          std::move(callback).Run(platform);
-        } else {
-          task_runner->PostTask(FROM_HERE,
-                                base::BindOnce(std::move(callback), platform));
-        }
-      },
-      base::RetainedRef(base::ThreadTaskRunnerHandle::Get()),
-      std::move(io_callback));
-  ui::OzonePlatform::RegisterStartupCallback(std::move(bounce_callback));
-}
-#endif  // defined(USE_OZONE)
-
 void OnGpuProcessHostDestroyedOnUI(int host_id, const std::string& message) {
   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
   GpuDataManagerImpl::GetInstance()->AddLogMessage(
@@ -621,18 +588,16 @@
     mojo::ScopedMessagePipeHandle interface_pipe) {
   if (interface_name ==
       discardable_memory::mojom::DiscardableSharedMemoryManager::Name_) {
-    BrowserThread::PostTask(
-        BrowserThread::UI, FROM_HERE,
-        base::BindOnce(
-            &BindDiscardableMemoryRequestOnUI,
-            discardable_memory::mojom::DiscardableSharedMemoryManagerRequest(
-                std::move(interface_pipe))));
+    BindDiscardableMemoryRequest(
+        discardable_memory::mojom::DiscardableSharedMemoryManagerRequest(
+            std::move(interface_pipe)));
     return;
   }
   process_->child_connection()->BindInterface(interface_name,
                                               std::move(interface_pipe));
 }
 
+#if defined(USE_OZONE)
 void GpuProcessHost::TerminateGpuProcess(const std::string& message) {
   // At the moment, this path is only used by Ozone/Wayland. Once others start
   // to use this, start to distinguish the origin of termination. By default,
@@ -641,6 +606,11 @@
   process_->TerminateOnBadMessageReceived(message);
 }
 
+void GpuProcessHost::SendGpuProcessMessage(IPC::Message* message) {
+  Send(message);
+}
+#endif  // defined(USE_OZONE)
+
 // static
 GpuProcessHost* GpuProcessHost::FromID(int host_id) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
@@ -803,60 +773,6 @@
       base::BindOnce(&OnGpuProcessHostDestroyedOnUI, host_id_, message));
 }
 
-#if defined(USE_OZONE)
-void GpuProcessHost::InitOzone() {
-  // Ozone needs to send the primary DRM device to GPU process as early as
-  // possible to ensure the latter always has a valid device. crbug.com/608839
-  // When running with mus, the OzonePlatform may not have been created yet. So
-  // defer the callback until OzonePlatform instance is created.
-  bool using_mojo = true;
-#if defined(OS_CHROMEOS)
-  using_mojo = features::IsOzoneDrmMojo();
-#endif
-  if (using_mojo) {
-    // TODO(rjkroege): Remove the legacy IPC code paths when no longer
-    // necessary. https://crbug.com/806092
-    auto interface_binder = base::BindRepeating(&GpuProcessHost::BindInterface,
-                                                weak_ptr_factory_.GetWeakPtr());
-    auto terminate_cb = base::BindOnce(&GpuProcessHost::TerminateGpuProcess,
-                                       weak_ptr_factory_.GetWeakPtr());
-
-    auto io_callback = base::BindOnce(
-        [](const base::RepeatingCallback<void(const std::string&,
-                                              mojo::ScopedMessagePipeHandle)>&
-               interface_binder,
-           base::OnceCallback<void(const std::string&)> terminate_cb,
-           ui::OzonePlatform* platform) {
-          DCHECK_CURRENTLY_ON(BrowserThread::IO);
-          platform->GetGpuPlatformSupportHost()->OnGpuServiceLaunched(
-              BrowserThread::GetTaskRunnerForThread(BrowserThread::UI),
-              BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
-              interface_binder, std::move(terminate_cb));
-        },
-        interface_binder, std::move(terminate_cb));
-
-    OzoneRegisterStartupCallbackHelper(std::move(io_callback));
-  } else {
-    auto send_callback = base::BindRepeating(&SendGpuProcessMessage,
-                                             weak_ptr_factory_.GetWeakPtr());
-    // Create the callback that should run on the current thread (i.e. IO
-    // thread).
-    auto io_callback = base::BindOnce(
-        [](int host_id,
-           const base::RepeatingCallback<void(IPC::Message*)>& send_callback,
-           ui::OzonePlatform* platform) {
-          DCHECK_CURRENTLY_ON(BrowserThread::IO);
-          platform->GetGpuPlatformSupportHost()->OnGpuProcessLaunched(
-              host_id, BrowserThread::GetTaskRunnerForThread(BrowserThread::UI),
-              BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
-              send_callback);
-        },
-        host_id_, send_callback);
-    OzoneRegisterStartupCallbackHelper(std::move(io_callback));
-  }
-}
-#endif  // defined(USE_OZONE)
-
 bool GpuProcessHost::Init() {
   init_start_time_ = base::TimeTicks::Now();
 
@@ -908,13 +824,11 @@
   params.product = GetContentClient()->GetProduct();
   params.deadline_to_synchronize_surfaces =
       switches::GetDeadlineToSynchronizeSurfaces();
+  params.main_thread_task_runner =
+      BrowserThread::GetTaskRunnerForThread(BrowserThread::UI);
   gpu_host_ = std::make_unique<viz::GpuHostImpl>(
       this, process_->child_channel(), std::move(params));
 
-#if defined(USE_OZONE)
-  InitOzone();
-#endif  // defined(USE_OZONE)
-
 #if defined(OS_MACOSX)
   ca_transaction_gpu_coordinator_ = CATransactionGPUCoordinator::Create(this);
 #endif
diff --git a/content/browser/gpu/gpu_process_host.h b/content/browser/gpu/gpu_process_host.h
index 9f3dcb7..e56abaef 100644
--- a/content/browser/gpu/gpu_process_host.h
+++ b/content/browser/gpu/gpu_process_host.h
@@ -84,10 +84,6 @@
       bool force_create,
       const base::Callback<void(GpuProcessHost*)>& callback);
 
-  void BindInterface(const std::string& interface_name,
-                     mojo::ScopedMessagePipeHandle interface_pipe);
-  void TerminateGpuProcess(const std::string& message);
-
   // Get the GPU process host for the GPU process with the given ID. Returns
   // null if the process no longer exists.
   static GpuProcessHost* FromID(int host_id);
@@ -130,10 +126,6 @@
 
   bool Init();
 
-#if defined(USE_OZONE)
-  void InitOzone();
-#endif  // defined(USE_OZONE)
-
   // BrowserChildProcessHostDelegate implementation.
   bool OnMessageReceived(const IPC::Message& message) override;
   void OnChannelConnected(int32_t peer_pid) override;
@@ -163,8 +155,14 @@
   void BindDiscardableMemoryRequest(
       discardable_memory::mojom::DiscardableSharedMemoryManagerRequest request)
       override;
+  void BindInterface(const std::string& interface_name,
+                     mojo::ScopedMessagePipeHandle interface_pipe) override;
+#if defined(USE_OZONE)
+  void TerminateGpuProcess(const std::string& message) override;
+  void SendGpuProcessMessage(IPC::Message* message) override;
+#endif
 
-  // Message handlers.
+// Message handlers.
 #if defined(OS_ANDROID)
   void OnDestroyingVideoSurfaceAck();
 #endif
diff --git a/content/browser/renderer_host/media/video_capture_dependencies.cc b/content/browser/gpu/video_capture_dependencies.cc
similarity index 92%
rename from content/browser/renderer_host/media/video_capture_dependencies.cc
rename to content/browser/gpu/video_capture_dependencies.cc
index 26567c65..cb77162 100644
--- a/content/browser/renderer_host/media/video_capture_dependencies.cc
+++ b/content/browser/gpu/video_capture_dependencies.cc
@@ -2,11 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/browser/renderer_host/media/video_capture_dependencies.h"
+#include "content/browser/gpu/video_capture_dependencies.h"
 
 #include "content/browser/gpu/gpu_process_host.h"
 #include "content/public/browser/browser_thread.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
 
 namespace content {
 
diff --git a/content/browser/renderer_host/media/video_capture_dependencies.h b/content/browser/gpu/video_capture_dependencies.h
similarity index 63%
rename from content/browser/renderer_host/media/video_capture_dependencies.h
rename to content/browser/gpu/video_capture_dependencies.h
index 5804eef..ab169bb 100644
--- a/content/browser/renderer_host/media/video_capture_dependencies.h
+++ b/content/browser/gpu/video_capture_dependencies.h
@@ -2,16 +2,15 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_DEPENDENCIES_H_
-#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_DEPENDENCIES_H_
+#ifndef CONTENT_BROWSER_GPU_VIDEO_CAPTURE_DEPENDENCIES_H_
+#define CONTENT_BROWSER_GPU_VIDEO_CAPTURE_DEPENDENCIES_H_
 
 #include "content/common/content_export.h"
-#include "services/video_capture/public/mojom/device_factory.mojom.h"
 #include "services/viz/privileged/interfaces/gl/gpu_service.mojom.h"
 
 namespace content {
 
-// Browser-provided GPU dependencies for video capture.
+// Browser-process-provided GPU dependencies for video capture.
 class CONTENT_EXPORT VideoCaptureDependencies {
  public:
   static void CreateJpegDecodeAccelerator(
@@ -22,4 +21,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_DEPENDENCIES_H_
+#endif  // CONTENT_BROWSER_GPU_VIDEO_CAPTURE_DEPENDENCIES_H_
diff --git a/content/browser/message_port_provider.cc b/content/browser/message_port_provider.cc
index e5d8f66..70893810 100644
--- a/content/browser/message_port_provider.cc
+++ b/content/browser/message_port_provider.cc
@@ -9,7 +9,7 @@
 #include "content/browser/web_contents/web_contents_impl.h"
 #include "content/common/frame_messages.h"
 #include "content/public/browser/browser_thread.h"
-#include "third_party/blink/public/common/message_port/string_message_codec.h"
+#include "third_party/blink/public/common/messaging/string_message_codec.h"
 
 #if defined(OS_ANDROID)
 #include "base/android/jni_string.h"
diff --git a/content/browser/notifications/blink_notification_service_impl.cc b/content/browser/notifications/blink_notification_service_impl.cc
index 84f5070..78034b8 100644
--- a/content/browser/notifications/blink_notification_service_impl.cc
+++ b/content/browser/notifications/blink_notification_service_impl.cc
@@ -20,8 +20,8 @@
 #include "content/public/browser/platform_notification_service.h"
 #include "content/public/common/content_client.h"
 #include "content/public/common/content_features.h"
-#include "content/public/common/notification_resources.h"
-#include "content/public/common/platform_notification_data.h"
+#include "third_party/blink/public/common/notifications/notification_resources.h"
+#include "third_party/blink/public/common/notifications/platform_notification_data.h"
 #include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
 #include "url/gurl.h"
 
@@ -85,8 +85,8 @@
 
 void BlinkNotificationServiceImpl::DisplayNonPersistentNotification(
     const std::string& token,
-    const PlatformNotificationData& platform_notification_data,
-    const NotificationResources& notification_resources,
+    const blink::PlatformNotificationData& platform_notification_data,
+    const blink::NotificationResources& notification_resources,
     blink::mojom::NonPersistentNotificationListenerPtr event_listener_ptr) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (!ValidateNotificationResources(notification_resources))
@@ -143,7 +143,7 @@
 }
 
 bool BlinkNotificationServiceImpl::ValidateNotificationResources(
-    const NotificationResources& notification_resources) {
+    const blink::NotificationResources& notification_resources) {
   if (notification_resources.image.drawsNothing() ||
       base::FeatureList::IsEnabled(features::kNotificationContentImage))
     return true;
@@ -157,8 +157,8 @@
 
 void BlinkNotificationServiceImpl::DisplayPersistentNotification(
     int64_t service_worker_registration_id,
-    const PlatformNotificationData& platform_notification_data,
-    const NotificationResources& notification_resources,
+    const blink::PlatformNotificationData& platform_notification_data,
+    const blink::NotificationResources& notification_resources,
     DisplayPersistentNotificationCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
   if (!ValidateNotificationResources(notification_resources))
@@ -191,8 +191,8 @@
 void BlinkNotificationServiceImpl::DisplayPersistentNotificationOnIOThread(
     int64_t service_worker_registration_id,
     int64_t next_persistent_notification_id,
-    const PlatformNotificationData& platform_notification_data,
-    const NotificationResources& notification_resources,
+    const blink::PlatformNotificationData& platform_notification_data,
+    const blink::NotificationResources& notification_resources,
     DisplayPersistentNotificationCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
@@ -218,8 +218,8 @@
 void BlinkNotificationServiceImpl::
     DisplayPersistentNotificationWithIdOnIOThread(
         int64_t service_worker_registration_id,
-        const PlatformNotificationData& platform_notification_data,
-        const NotificationResources& notification_resources,
+        const blink::PlatformNotificationData& platform_notification_data,
+        const blink::NotificationResources& notification_resources,
         DisplayPersistentNotificationCallback callback,
         bool success,
         const std::string& notification_id) {
@@ -245,8 +245,8 @@
 void BlinkNotificationServiceImpl::
     DisplayPersistentNotificationWithServiceWorkerOnIOThread(
         const std::string& notification_id,
-        const PlatformNotificationData& platform_notification_data,
-        const NotificationResources& notification_resources,
+        const blink::PlatformNotificationData& platform_notification_data,
+        const blink::NotificationResources& notification_resources,
         DisplayPersistentNotificationCallback callback,
         blink::ServiceWorkerStatusCode service_worker_status,
         scoped_refptr<ServiceWorkerRegistration> registration) {
@@ -306,7 +306,7 @@
     // try to get notifications without permission, so return empty vectors
     // indicating that no (accessible) notifications exist at this time.
     std::move(callback).Run(std::vector<std::string>(),
-                            std::vector<PlatformNotificationData>());
+                            std::vector<blink::PlatformNotificationData>());
     return;
   }
 
@@ -332,7 +332,7 @@
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
 
   std::vector<std::string> ids;
-  std::vector<PlatformNotificationData> datas;
+  std::vector<blink::PlatformNotificationData> datas;
 
   for (const NotificationDatabaseData& database_data : notifications) {
     // An empty filter tag matches all, else we need an exact match.
diff --git a/content/browser/notifications/blink_notification_service_impl.h b/content/browser/notifications/blink_notification_service_impl.h
index aed37b1..1ae12ca 100644
--- a/content/browser/notifications/blink_notification_service_impl.h
+++ b/content/browser/notifications/blink_notification_service_impl.h
@@ -16,11 +16,14 @@
 #include "third_party/blink/public/platform/modules/permissions/permission_status.mojom.h"
 #include "url/origin.h"
 
+namespace blink {
+struct PlatformNotificationData;
+}
+
 namespace content {
 
 struct NotificationDatabaseData;
 class PlatformNotificationContextImpl;
-struct PlatformNotificationData;
 
 // Implementation of the NotificationService used for Web Notifications. Is
 // responsible for displaying, updating and reading of both non-persistent
@@ -41,14 +44,14 @@
   void GetPermissionStatus(GetPermissionStatusCallback callback) override;
   void DisplayNonPersistentNotification(
       const std::string& token,
-      const PlatformNotificationData& platform_notification_data,
-      const NotificationResources& notification_resources,
+      const blink::PlatformNotificationData& platform_notification_data,
+      const blink::NotificationResources& notification_resources,
       blink::mojom::NonPersistentNotificationListenerPtr listener_ptr) override;
   void CloseNonPersistentNotification(const std::string& token) override;
   void DisplayPersistentNotification(
       int64_t service_worker_registration_id,
-      const PlatformNotificationData& platform_notification_data,
-      const NotificationResources& notification_resources,
+      const blink::PlatformNotificationData& platform_notification_data,
+      const blink::NotificationResources& notification_resources,
       DisplayPersistentNotificationCallback) override;
   void ClosePersistentNotification(const std::string& notification_id) override;
   void GetNotifications(int64_t service_worker_registration_id,
@@ -67,27 +70,27 @@
   // destroy |this| by calling OnConnectionError() directly, then return false.
   // So, please do not touch |this| again after you got a false return value.
   bool ValidateNotificationResources(
-      const NotificationResources& notification_resources);
+      const blink::NotificationResources& notification_resources);
 
   void DisplayPersistentNotificationOnIOThread(
       int64_t service_worker_registration_id,
       int64_t persistent_notification_id,
-      const PlatformNotificationData& platform_notification_data,
-      const NotificationResources& notification_resources,
+      const blink::PlatformNotificationData& platform_notification_data,
+      const blink::NotificationResources& notification_resources,
       DisplayPersistentNotificationCallback callback);
 
   void DisplayPersistentNotificationWithIdOnIOThread(
       int64_t service_worker_registration_id,
-      const PlatformNotificationData& platform_notification_data,
-      const NotificationResources& notification_resources,
+      const blink::PlatformNotificationData& platform_notification_data,
+      const blink::NotificationResources& notification_resources,
       DisplayPersistentNotificationCallback callback,
       bool success,
       const std::string& notification_id);
 
   void DisplayPersistentNotificationWithServiceWorkerOnIOThread(
       const std::string& notification_id,
-      const PlatformNotificationData& platform_notification_data,
-      const NotificationResources& notification_resources,
+      const blink::PlatformNotificationData& platform_notification_data,
+      const blink::NotificationResources& notification_resources,
       DisplayPersistentNotificationCallback callback,
       blink::ServiceWorkerStatusCode service_worker_status,
       scoped_refptr<ServiceWorkerRegistration> registration);
diff --git a/content/browser/notifications/blink_notification_service_impl_unittest.cc b/content/browser/notifications/blink_notification_service_impl_unittest.cc
index 8de2804..9985cfe 100644
--- a/content/browser/notifications/blink_notification_service_impl_unittest.cc
+++ b/content/browser/notifications/blink_notification_service_impl_unittest.cc
@@ -242,7 +242,7 @@
   void DidGetNotifications(
       base::OnceClosure quit_closure,
       const std::vector<std::string>& notification_ids,
-      const std::vector<PlatformNotificationData>& notification_datas) {
+      const std::vector<blink::PlatformNotificationData>& notification_datas) {
     get_notifications_callback_result_ = notification_ids;
     std::move(quit_closure).Run();
   }
@@ -264,8 +264,8 @@
 
   void DisplayNonPersistentNotification(
       const std::string& token,
-      const PlatformNotificationData& platform_notification_data,
-      const NotificationResources& notification_resources,
+      const blink::PlatformNotificationData& platform_notification_data,
+      const blink::NotificationResources& notification_resources,
       blink::mojom::NonPersistentNotificationListenerPtr event_listener_ptr) {
     notification_service_ptr_->DisplayNonPersistentNotification(
         token, platform_notification_data, notification_resources,
@@ -279,8 +279,8 @@
 
   void DisplayPersistentNotificationSync(
       int64_t service_worker_registration_id,
-      const PlatformNotificationData& platform_notification_data,
-      const NotificationResources& notification_resources) {
+      const blink::PlatformNotificationData& platform_notification_data,
+      const blink::NotificationResources& notification_resources) {
     base::RunLoop run_loop;
     notification_service_ptr_.set_connection_error_handler(
         run_loop.QuitClosure());
@@ -427,7 +427,8 @@
   SetPermissionStatus(blink::mojom::PermissionStatus::GRANTED);
 
   DisplayNonPersistentNotification(
-      "token", PlatformNotificationData(), NotificationResources(),
+      "token", blink::PlatformNotificationData(),
+      blink::NotificationResources(),
       non_persistent_notification_listener_.GetPtr());
 
   EXPECT_EQ(1u, GetDisplayedNotifications().size());
@@ -438,7 +439,8 @@
   SetPermissionStatus(blink::mojom::PermissionStatus::DENIED);
 
   DisplayNonPersistentNotification(
-      "token", PlatformNotificationData(), NotificationResources(),
+      "token", blink::PlatformNotificationData(),
+      blink::NotificationResources(),
       non_persistent_notification_listener_.GetPtr());
 
   EXPECT_EQ(0u, GetDisplayedNotifications().size());
@@ -448,10 +450,10 @@
        DisplayNonPersistentNotificationWithContentImageSwitchOn) {
   SetPermissionStatus(blink::mojom::PermissionStatus::GRANTED);
 
-  NotificationResources resources;
+  blink::NotificationResources resources;
   resources.image = CreateBitmap(200, 100, SK_ColorMAGENTA);
   DisplayNonPersistentNotification(
-      "token", PlatformNotificationData(), resources,
+      "token", blink::PlatformNotificationData(), resources,
       non_persistent_notification_listener_.GetPtr());
 
   EXPECT_EQ(1u, GetDisplayedNotifications().size());
@@ -465,10 +467,10 @@
   SetPermissionStatus(blink::mojom::PermissionStatus::GRANTED);
 
   ASSERT_TRUE(bad_messages_.empty());
-  NotificationResources resources;
+  blink::NotificationResources resources;
   resources.image = CreateBitmap(200, 100, SK_ColorMAGENTA);
   DisplayNonPersistentNotification(
-      "token", PlatformNotificationData(), resources,
+      "token", blink::PlatformNotificationData(), resources,
       non_persistent_notification_listener_.GetPtr());
   EXPECT_EQ(1u, bad_messages_.size());
   EXPECT_EQ(kBadMessageImproperNotificationImage, bad_messages_[0]);
@@ -481,10 +483,10 @@
   scoped_refptr<ServiceWorkerRegistration> registration;
   RegisterServiceWorker(&registration);
 
-  NotificationResources resources;
+  blink::NotificationResources resources;
   resources.image = CreateBitmap(200, 100, SK_ColorMAGENTA);
-  DisplayPersistentNotificationSync(registration->id(),
-                                    PlatformNotificationData(), resources);
+  DisplayPersistentNotificationSync(
+      registration->id(), blink::PlatformNotificationData(), resources);
 
   EXPECT_EQ(blink::mojom::PersistentNotificationError::NONE,
             display_persistent_callback_result_);
@@ -506,10 +508,10 @@
   RegisterServiceWorker(&registration);
 
   ASSERT_TRUE(bad_messages_.empty());
-  NotificationResources resources;
+  blink::NotificationResources resources;
   resources.image = CreateBitmap(200, 100, SK_ColorMAGENTA);
-  DisplayPersistentNotificationSync(registration->id(),
-                                    PlatformNotificationData(), resources);
+  DisplayPersistentNotificationSync(
+      registration->id(), blink::PlatformNotificationData(), resources);
   EXPECT_EQ(1u, bad_messages_.size());
   EXPECT_EQ(kBadMessageImproperNotificationImage, bad_messages_[0]);
 }
@@ -521,8 +523,9 @@
   scoped_refptr<ServiceWorkerRegistration> registration;
   RegisterServiceWorker(&registration);
 
-  DisplayPersistentNotificationSync(
-      registration->id(), PlatformNotificationData(), NotificationResources());
+  DisplayPersistentNotificationSync(registration->id(),
+                                    blink::PlatformNotificationData(),
+                                    blink::NotificationResources());
 
   EXPECT_EQ(blink::mojom::PersistentNotificationError::NONE,
             display_persistent_callback_result_);
@@ -539,8 +542,9 @@
   scoped_refptr<ServiceWorkerRegistration> registration;
   RegisterServiceWorker(&registration);
 
-  DisplayPersistentNotificationSync(
-      registration->id(), PlatformNotificationData(), NotificationResources());
+  DisplayPersistentNotificationSync(registration->id(),
+                                    blink::PlatformNotificationData(),
+                                    blink::NotificationResources());
 
   ASSERT_EQ(blink::mojom::PersistentNotificationError::NONE,
             display_persistent_callback_result_);
@@ -566,8 +570,9 @@
   scoped_refptr<ServiceWorkerRegistration> registration;
   RegisterServiceWorker(&registration);
 
-  DisplayPersistentNotificationSync(
-      registration->id(), PlatformNotificationData(), NotificationResources());
+  DisplayPersistentNotificationSync(registration->id(),
+                                    blink::PlatformNotificationData(),
+                                    blink::NotificationResources());
 
   ASSERT_EQ(blink::mojom::PersistentNotificationError::NONE,
             display_persistent_callback_result_);
@@ -599,8 +604,9 @@
   scoped_refptr<ServiceWorkerRegistration> registration;
   RegisterServiceWorker(&registration);
 
-  DisplayPersistentNotificationSync(
-      registration->id(), PlatformNotificationData(), NotificationResources());
+  DisplayPersistentNotificationSync(registration->id(),
+                                    blink::PlatformNotificationData(),
+                                    blink::NotificationResources());
 
   EXPECT_EQ(blink::mojom::PersistentNotificationError::PERMISSION_DENIED,
             display_persistent_callback_result_);
@@ -618,11 +624,13 @@
   scoped_refptr<ServiceWorkerRegistration> registration;
   RegisterServiceWorker(&registration);
 
-  DisplayPersistentNotificationSync(
-      registration->id(), PlatformNotificationData(), NotificationResources());
+  DisplayPersistentNotificationSync(registration->id(),
+                                    blink::PlatformNotificationData(),
+                                    blink::NotificationResources());
 
-  DisplayPersistentNotificationSync(
-      registration->id(), PlatformNotificationData(), NotificationResources());
+  DisplayPersistentNotificationSync(registration->id(),
+                                    blink::PlatformNotificationData(),
+                                    blink::NotificationResources());
 
   // Wait for service to receive all the Display calls.
   RunAllTasksUntilIdle();
@@ -639,8 +647,9 @@
   EXPECT_EQ(
       0u, GetNotificationsSync(registration->id(), "" /* filter_tag */).size());
 
-  DisplayPersistentNotificationSync(
-      registration->id(), PlatformNotificationData(), NotificationResources());
+  DisplayPersistentNotificationSync(registration->id(),
+                                    blink::PlatformNotificationData(),
+                                    blink::NotificationResources());
 
   // Wait for service to receive all the Display calls.
   RunAllTasksUntilIdle();
@@ -655,8 +664,9 @@
   scoped_refptr<ServiceWorkerRegistration> registration;
   RegisterServiceWorker(&registration);
 
-  DisplayPersistentNotificationSync(
-      registration->id(), PlatformNotificationData(), NotificationResources());
+  DisplayPersistentNotificationSync(registration->id(),
+                                    blink::PlatformNotificationData(),
+                                    blink::NotificationResources());
 
   // Wait for service to receive all the Display calls.
   RunAllTasksUntilIdle();
@@ -673,18 +683,19 @@
   scoped_refptr<ServiceWorkerRegistration> registration;
   RegisterServiceWorker(&registration);
 
-  PlatformNotificationData platform_notification_data;
+  blink::PlatformNotificationData platform_notification_data;
   platform_notification_data.tag = "tagA";
 
-  PlatformNotificationData other_platform_notification_data;
+  blink::PlatformNotificationData other_platform_notification_data;
   other_platform_notification_data.tag = "tagB";
 
-  DisplayPersistentNotificationSync(
-      registration->id(), platform_notification_data, NotificationResources());
+  DisplayPersistentNotificationSync(registration->id(),
+                                    platform_notification_data,
+                                    blink::NotificationResources());
 
   DisplayPersistentNotificationSync(registration->id(),
                                     other_platform_notification_data,
-                                    NotificationResources());
+                                    blink::NotificationResources());
 
   // Wait for service to receive all the Display calls.
   RunAllTasksUntilIdle();
diff --git a/content/browser/notifications/notification_database_data.proto b/content/browser/notifications/notification_database_data.proto
index 6a631180..e521c88 100644
--- a/content/browser/notifications/notification_database_data.proto
+++ b/content/browser/notifications/notification_database_data.proto
@@ -35,11 +35,11 @@
   optional int64 time_until_close_millis = 12;
   optional ClosedReason closed_reason = 13;
 
-  // A notification action, corresponds to content::PlatformNotificationAction.
+  // A notification action, corresponds to blink::PlatformNotificationAction.
   //
   // Next tag: 6
   message NotificationAction {
-    // Corresponds to PlatformNotificationActionType.
+    // Corresponds to blink::PlatformNotificationActionType.
     enum Type {
       BUTTON = 0;
       TEXT = 1;
@@ -53,7 +53,7 @@
   }
 
   // Actual data payload of the notification. This message is the protocol
-  // buffer meant to serialize the content::PlatformNotificationData structure.
+  // buffer meant to serialize the blink::PlatformNotificationData structure.
   //
   // Next tag: 16
   message NotificationData {
diff --git a/content/browser/notifications/notification_database_data_conversions.cc b/content/browser/notifications/notification_database_data_conversions.cc
index 9049630..83b0b0043 100644
--- a/content/browser/notifications/notification_database_data_conversions.cc
+++ b/content/browser/notifications/notification_database_data_conversions.cc
@@ -60,7 +60,8 @@
       break;
   }
 
-  PlatformNotificationData* notification_data = &output->notification_data;
+  blink::PlatformNotificationData* notification_data =
+      &output->notification_data;
   const NotificationDatabaseDataProto::NotificationData& payload =
       message.notification_data();
 
@@ -69,14 +70,15 @@
   switch (payload.direction()) {
     case NotificationDatabaseDataProto::NotificationData::LEFT_TO_RIGHT:
       notification_data->direction =
-          PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT;
+          blink::PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT;
       break;
     case NotificationDatabaseDataProto::NotificationData::RIGHT_TO_LEFT:
       notification_data->direction =
-          PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT;
+          blink::PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT;
       break;
     case NotificationDatabaseDataProto::NotificationData::AUTO:
-      notification_data->direction = PlatformNotificationData::DIRECTION_AUTO;
+      notification_data->direction =
+          blink::PlatformNotificationData::DIRECTION_AUTO;
       break;
   }
 
@@ -110,14 +112,14 @@
   notification_data->actions.clear();
 
   for (const auto& payload_action : payload.actions()) {
-    PlatformNotificationAction action;
+    blink::PlatformNotificationAction action;
 
     switch (payload_action.type()) {
       case NotificationDatabaseDataProto::NotificationAction::BUTTON:
-        action.type = PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON;
+        action.type = blink::PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON;
         break;
       case NotificationDatabaseDataProto::NotificationAction::TEXT:
-        action.type = PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT;
+        action.type = blink::PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT;
         break;
       default:
         NOTREACHED();
@@ -143,20 +145,21 @@
   std::unique_ptr<NotificationDatabaseDataProto::NotificationData> payload(
       new NotificationDatabaseDataProto::NotificationData());
 
-  const PlatformNotificationData& notification_data = input.notification_data;
+  const blink::PlatformNotificationData& notification_data =
+      input.notification_data;
 
   payload->set_title(base::UTF16ToUTF8(notification_data.title));
 
   switch (notification_data.direction) {
-    case PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT:
+    case blink::PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT:
       payload->set_direction(
           NotificationDatabaseDataProto::NotificationData::LEFT_TO_RIGHT);
       break;
-    case PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT:
+    case blink::PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT:
       payload->set_direction(
           NotificationDatabaseDataProto::NotificationData::RIGHT_TO_LEFT);
       break;
-    case PlatformNotificationData::DIRECTION_AUTO:
+    case blink::PlatformNotificationData::DIRECTION_AUTO:
       payload->set_direction(
           NotificationDatabaseDataProto::NotificationData::AUTO);
       break;
@@ -182,16 +185,17 @@
                       notification_data.data.size());
   }
 
-  for (const PlatformNotificationAction& action : notification_data.actions) {
+  for (const blink::PlatformNotificationAction& action :
+       notification_data.actions) {
     NotificationDatabaseDataProto::NotificationAction* payload_action =
         payload->add_actions();
 
     switch (action.type) {
-      case PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON:
+      case blink::PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON:
         payload_action->set_type(
             NotificationDatabaseDataProto::NotificationAction::BUTTON);
         break;
-      case PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT:
+      case blink::PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT:
         payload_action->set_type(
             NotificationDatabaseDataProto::NotificationAction::TEXT);
         break;
diff --git a/content/browser/notifications/notification_database_data_unittest.cc b/content/browser/notifications/notification_database_data_unittest.cc
index 9de61d5..db02412 100644
--- a/content/browser/notifications/notification_database_data_unittest.cc
+++ b/content/browser/notifications/notification_database_data_unittest.cc
@@ -30,8 +30,8 @@
 const int kTimeUntilLastClickMillis = 22222;
 const int kTimeUntilCloseMillis = 33333;
 
-const PlatformNotificationActionType kNotificationActionType =
-    PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT;
+const blink::PlatformNotificationActionType kNotificationActionType =
+    blink::PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT;
 const char kOrigin[] = "https://example.com/";
 const char kNotificationTitle[] = "My Notification";
 const char kNotificationLang[] = "nl";
@@ -54,10 +54,10 @@
   std::vector<char> developer_data(
       kNotificationData, kNotificationData + base::size(kNotificationData));
 
-  PlatformNotificationData notification_data;
+  blink::PlatformNotificationData notification_data;
   notification_data.title = base::ASCIIToUTF16(kNotificationTitle);
   notification_data.direction =
-      PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT;
+      blink::PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT;
   notification_data.lang = kNotificationLang;
   notification_data.body = base::ASCIIToUTF16(kNotificationBody);
   notification_data.tag = kNotificationTag;
@@ -71,7 +71,7 @@
   notification_data.require_interaction = true;
   notification_data.data = developer_data;
   for (size_t i = 0; i < blink::kWebNotificationMaxActions; i++) {
-    PlatformNotificationAction notification_action;
+    blink::PlatformNotificationAction notification_action;
     notification_action.type = kNotificationActionType;
     notification_action.action = base::NumberToString(i);
     notification_action.title = base::NumberToString16(i);
@@ -128,7 +128,7 @@
             copied_data.time_until_close_millis);
   EXPECT_EQ(database_data.closed_reason, copied_data.closed_reason);
 
-  const PlatformNotificationData& copied_notification_data =
+  const blink::PlatformNotificationData& copied_notification_data =
       copied_data.notification_data;
 
   EXPECT_EQ(notification_data.title, copied_notification_data.title);
@@ -199,14 +199,14 @@
 }
 
 TEST(NotificationDatabaseDataTest, SerializeAndDeserializeActionTypes) {
-  PlatformNotificationActionType action_types[] = {
-      PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON,
-      PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT};
+  blink::PlatformNotificationActionType action_types[] = {
+      blink::PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON,
+      blink::PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT};
 
-  for (PlatformNotificationActionType action_type : action_types) {
-    PlatformNotificationData notification_data;
+  for (blink::PlatformNotificationActionType action_type : action_types) {
+    blink::PlatformNotificationData notification_data;
 
-    PlatformNotificationAction action;
+    blink::PlatformNotificationAction action;
     action.type = action_type;
     notification_data.actions.push_back(action);
 
@@ -226,13 +226,13 @@
 }
 
 TEST(NotificationDatabaseDataTest, SerializeAndDeserializeDirections) {
-  PlatformNotificationData::Direction directions[] = {
-      PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT,
-      PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT,
-      PlatformNotificationData::DIRECTION_AUTO};
+  blink::PlatformNotificationData::Direction directions[] = {
+      blink::PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT,
+      blink::PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT,
+      blink::PlatformNotificationData::DIRECTION_AUTO};
 
   for (size_t i = 0; i < base::size(directions); ++i) {
-    PlatformNotificationData notification_data;
+    blink::PlatformNotificationData notification_data;
     notification_data.direction = directions[i];
 
     NotificationDatabaseData database_data;
@@ -273,11 +273,11 @@
 }
 
 TEST(NotificationDatabaseDataTest, SerializeAndDeserializeNullPlaceholder) {
-  PlatformNotificationAction action;
+  blink::PlatformNotificationAction action;
   action.type = kNotificationActionType;
   action.placeholder = base::NullableString16();  // null string.
 
-  PlatformNotificationData notification_data;
+  blink::PlatformNotificationData notification_data;
   notification_data.actions.push_back(action);
 
   NotificationDatabaseData database_data;
diff --git a/content/browser/notifications/notification_database_unittest.cc b/content/browser/notifications/notification_database_unittest.cc
index fb0d6cb..8f0978c 100644
--- a/content/browser/notifications/notification_database_unittest.cc
+++ b/content/browser/notifications/notification_database_unittest.cc
@@ -13,9 +13,9 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "content/public/browser/notification_database_data.h"
-#include "content/public/common/platform_notification_data.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/notifications/platform_notification_data.h"
 #include "third_party/leveldatabase/src/include/leveldb/db.h"
 #include "third_party/leveldatabase/src/include/leveldb/write_batch.h"
 #include "url/gurl.h"
@@ -283,10 +283,10 @@
 
   GURL origin("https://example.com");
 
-  PlatformNotificationData notification_data;
+  blink::PlatformNotificationData notification_data;
   notification_data.title = base::UTF8ToUTF16("My Notification");
   notification_data.direction =
-      PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT;
+      blink::PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT;
   notification_data.lang = "nl-NL";
   notification_data.body = base::UTF8ToUTF16("Hello, world!");
   notification_data.tag = "replace id";
@@ -318,7 +318,7 @@
   EXPECT_EQ(database_data.service_worker_registration_id,
             read_database_data.service_worker_registration_id);
 
-  const PlatformNotificationData& read_notification_data =
+  const blink::PlatformNotificationData& read_notification_data =
       read_database_data.notification_data;
 
   EXPECT_EQ(notification_data.title, read_notification_data.title);
diff --git a/content/browser/notifications/notification_event_dispatcher_impl.cc b/content/browser/notifications/notification_event_dispatcher_impl.cc
index d8acb32..0b958db8 100644
--- a/content/browser/notifications/notification_event_dispatcher_impl.cc
+++ b/content/browser/notifications/notification_event_dispatcher_impl.cc
@@ -18,7 +18,7 @@
 #include "content/public/browser/render_process_host.h"
 #include "content/public/browser/storage_partition.h"
 #include "content/public/common/persistent_notification_status.h"
-#include "content/public/common/platform_notification_data.h"
+#include "third_party/blink/public/common/notifications/platform_notification_data.h"
 
 namespace content {
 namespace {
diff --git a/content/browser/notifications/platform_notification_context_unittest.cc b/content/browser/notifications/platform_notification_context_unittest.cc
index 1e56693..761d302 100644
--- a/content/browser/notifications/platform_notification_context_unittest.cc
+++ b/content/browser/notifications/platform_notification_context_unittest.cc
@@ -15,12 +15,12 @@
 #include "content/browser/service_worker/service_worker_context_wrapper.h"
 #include "content/common/service_worker/service_worker_types.h"
 #include "content/public/browser/notification_database_data.h"
-#include "content/public/common/notification_resources.h"
 #include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "content/test/mock_platform_notification_service.h"
 #include "content/test/test_content_browser_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/notifications/notification_resources.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
 #include "url/gurl.h"
 
@@ -530,8 +530,8 @@
   NotificationDatabaseData notification_database_data;
   notification_database_data.service_worker_registration_id =
       kFakeServiceWorkerRegistrationId;
-  PlatformNotificationData notification_data;
-  content::NotificationResources notification_resources;
+  blink::PlatformNotificationData notification_data;
+  blink::NotificationResources notification_resources;
 
   context->WriteNotificationData(
       next_persistent_notification_id(), kFakeServiceWorkerRegistrationId,
diff --git a/content/browser/payments/payment_app_installer.cc b/content/browser/payments/payment_app_installer.cc
index 6a6e31b..4f1b24f 100644
--- a/content/browser/payments/payment_app_installer.cc
+++ b/content/browser/payments/payment_app_installer.cc
@@ -4,6 +4,8 @@
 
 #include "content/browser/payments/payment_app_installer.h"
 
+#include <utility>
+
 #include "base/bind.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
@@ -26,12 +28,10 @@
     : public WebContentsObserver,
       public base::RefCountedThreadSafe<SelfDeleteInstaller> {
  public:
-  SelfDeleteInstaller(WebContents* web_contents,
-                      const std::string& app_name,
+  SelfDeleteInstaller(const std::string& app_name,
                       const std::string& app_icon,
                       const GURL& sw_url,
                       const GURL& scope,
-                      bool use_cache,
                       const std::string& method,
                       PaymentAppInstaller::InstallPaymentAppCallback callback)
       : app_name_(app_name),
@@ -41,6 +41,12 @@
         method_(method),
         callback_(std::move(callback)) {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
+  }
+
+  void Init(WebContents* web_contents, bool use_cache) {
+    DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+    AddRef();  // Balanced by Release() in FinishInstallation.
 
     // TODO(crbug.com/782270): Listen for web contents events to terminate
     // installation early.
@@ -66,7 +72,7 @@
           blink::mojom::ServiceWorkerUpdateViaCache::kNone;
     }
     service_worker_context->RegisterServiceWorker(
-        sw_url, option,
+        sw_url_, option,
         base::BindOnce(&SelfDeleteInstaller::OnRegisterServiceWorkerResult,
                        this));
   }
@@ -184,6 +190,7 @@
     }
 
     Observe(nullptr);
+    Release();  // Balanced by AddRef() in the constructor.
   }
 
   std::string app_name_;
@@ -212,8 +219,9 @@
                                   InstallPaymentAppCallback callback) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  new SelfDeleteInstaller(web_contents, app_name, app_icon, sw_url, scope,
-                          use_cache, method, std::move(callback));
+  auto installer = base::MakeRefCounted<SelfDeleteInstaller>(
+      app_name, app_icon, sw_url, scope, method, std::move(callback));
+  installer->Init(web_contents, use_cache);
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc b/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
index ffa3e8c..098a108 100644
--- a/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
+++ b/content/browser/renderer_host/media/in_process_video_capture_device_launcher.cc
@@ -11,9 +11,9 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/strings/stringprintf.h"
 #include "build/build_config.h"
+#include "content/browser/gpu/video_capture_dependencies.h"
 #include "content/browser/renderer_host/media/in_process_launched_video_capture_device.h"
 #include "content/browser/renderer_host/media/video_capture_controller.h"
-#include "content/browser/renderer_host/media/video_capture_dependencies.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/desktop_media_id.h"
 #include "content/public/common/media_stream_request.h"
diff --git a/content/browser/renderer_host/media/media_stream_manager.cc b/content/browser/renderer_host/media/media_stream_manager.cc
index 6d96bb8..81c25c70 100644
--- a/content/browser/renderer_host/media/media_stream_manager.cc
+++ b/content/browser/renderer_host/media/media_stream_manager.cc
@@ -29,6 +29,7 @@
 #include "build/build_config.h"
 #include "content/browser/child_process_security_policy_impl.h"
 #include "content/browser/gpu/gpu_process_host.h"
+#include "content/browser/gpu/video_capture_dependencies.h"
 #include "content/browser/renderer_host/media/audio_input_device_manager.h"
 #include "content/browser/renderer_host/media/audio_service_listener.h"
 #include "content/browser/renderer_host/media/in_process_video_capture_provider.h"
@@ -36,7 +37,6 @@
 #include "content/browser/renderer_host/media/media_devices_manager.h"
 #include "content/browser/renderer_host/media/media_stream_ui_proxy.h"
 #include "content/browser/renderer_host/media/service_video_capture_provider.h"
-#include "content/browser/renderer_host/media/video_capture_dependencies.h"
 #include "content/browser/renderer_host/media/video_capture_manager.h"
 #include "content/browser/renderer_host/media/video_capture_provider_switcher.h"
 #include "content/browser/renderer_host/render_process_host_impl.h"
diff --git a/content/browser/renderer_host/media/service_video_capture_provider.cc b/content/browser/renderer_host/media/service_video_capture_provider.cc
index 34445f2..f3cf7f94 100644
--- a/content/browser/renderer_host/media/service_video_capture_provider.cc
+++ b/content/browser/renderer_host/media/service_video_capture_provider.cc
@@ -5,10 +5,10 @@
 #include "content/browser/renderer_host/media/service_video_capture_provider.h"
 
 #include "content/browser/renderer_host/media/service_video_capture_device_launcher.h"
-#include "content/browser/renderer_host/media/video_capture_dependencies.h"
 #include "content/browser/renderer_host/media/video_capture_factory_delegate.h"
 #include "content/common/child_process_host_impl.h"
 #include "content/public/browser/browser_thread.h"
+#include "content/public/browser/delegate_to_browser_gpu_service_accelerator_factory.h"
 #include "content/public/common/service_manager_connection.h"
 #include "mojo/public/cpp/bindings/callback_helpers.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
@@ -47,19 +47,10 @@
   std::unique_ptr<service_manager::Connector> connector_;
 };
 
-class DelegateToBrowserGpuServiceAcceleratorFactory
-    : public video_capture::mojom::AcceleratorFactory {
- public:
-  void CreateJpegDecodeAccelerator(
-      media::mojom::JpegDecodeAcceleratorRequest jda_request) override {
-    content::VideoCaptureDependencies::CreateJpegDecodeAccelerator(
-        std::move(jda_request));
-  }
-};
-
 std::unique_ptr<video_capture::mojom::AcceleratorFactory>
 CreateAcceleratorFactory() {
-  return std::make_unique<DelegateToBrowserGpuServiceAcceleratorFactory>();
+  return std::make_unique<
+      content::DelegateToBrowserGpuServiceAcceleratorFactory>();
 }
 
 }  // anonymous namespace
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index e4bafbdf..25c1510 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -522,8 +522,8 @@
         session_storage_namespaces_awaiting_close_.release());
   }
 
-  void Hold(const SessionStorageNamespaceMap& sessions, int view_route_id) {
-    (*session_storage_namespaces_awaiting_close_)[view_route_id] = sessions;
+  void Hold(const SessionStorageNamespaceMap& sessions, int widget_route_id) {
+    (*session_storage_namespaces_awaiting_close_)[widget_route_id] = sessions;
   }
 
   void Release(int old_route_id) {
@@ -4215,7 +4215,7 @@
 void RenderProcessHostImpl::ReleaseOnCloseACK(
     RenderProcessHost* host,
     const SessionStorageNamespaceMap& sessions,
-    int view_route_id) {
+    int widget_route_id) {
   DCHECK(host);
   if (sessions.empty())
     return;
@@ -4225,7 +4225,7 @@
     holder = new SessionStorageHolder();
     host->SetUserData(kSessionStorageHolderKey, base::WrapUnique(holder));
   }
-  holder->Hold(sessions, view_route_id);
+  holder->Hold(sessions, widget_route_id);
 }
 
 void RenderProcessHostImpl::SuddenTerminationChanged(bool enabled) {
@@ -4467,12 +4467,12 @@
   base::RecordComputedAction(action);
 }
 
-void RenderProcessHostImpl::OnCloseACK(int old_route_id) {
+void RenderProcessHostImpl::OnCloseACK(int closed_widget_route_id) {
   SessionStorageHolder* holder =
       static_cast<SessionStorageHolder*>(GetUserData(kSessionStorageHolderKey));
   if (!holder)
     return;
-  holder->Release(old_route_id);
+  holder->Release(closed_widget_route_id);
 }
 
 void RenderProcessHostImpl::OnGpuSwitched() {
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index 37bc9b7..416e128b 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -255,11 +255,12 @@
 
   // Used to extend the lifetime of the sessions until the render view
   // in the renderer is fully closed. This is static because its also called
-  // with mock hosts as input in test cases.
-  static void ReleaseOnCloseACK(
-      RenderProcessHost* host,
-      const SessionStorageNamespaceMap& sessions,
-      int view_route_id);
+  // with mock hosts as input in test cases. The RenderWidget routing associated
+  // with the view is used as the key since the ViewMsg_Close and
+  // ViewHostMsg_Close_ACK logic is centered around RenderWidgets.
+  static void ReleaseOnCloseACK(RenderProcessHost* host,
+                                const SessionStorageNamespaceMap& sessions,
+                                int widget_route_id);
 
   // Register/unregister the host identified by the host id in the global host
   // list.
@@ -532,7 +533,7 @@
 
   // Control message handlers.
   void OnUserMetricsRecordAction(const std::string& action);
-  void OnCloseACK(int old_route_id);
+  void OnCloseACK(int closed_widget_route_id);
 
   // Generates a command line to be used to spawn a renderer and appends the
   // results to |*command_line|.
diff --git a/content/browser/renderer_host/render_view_host_impl.cc b/content/browser/renderer_host/render_view_host_impl.cc
index a25a92f..8a42ffd 100644
--- a/content/browser/renderer_host/render_view_host_impl.cc
+++ b/content/browser/renderer_host/render_view_host_impl.cc
@@ -809,9 +809,8 @@
   // in the renderer has wound down.
   if (GetProcess()->IsInitializedAndNotDead()) {
     RenderProcessHostImpl::ReleaseOnCloseACK(
-        GetProcess(),
-        delegate_->GetSessionStorageNamespaceMap(),
-        GetRoutingID());
+        GetProcess(), delegate_->GetSessionStorageNamespaceMap(),
+        GetWidget()->GetRoutingID());
   }
 
   GetWidget()->ShutdownAndDestroyWidget(false);
@@ -933,11 +932,6 @@
   return is_active_;
 }
 
-void RenderViewHostImpl::RenderWidgetDidShutdown() {
-  bool rv = Send(new ViewMsg_Close(GetRoutingID()));
-  DCHECK(rv);
-}
-
 WebPreferences RenderViewHostImpl::GetWebkitPreferences() {
   if (!web_preferences_.get()) {
     OnWebkitPreferencesChanged();
diff --git a/content/browser/renderer_host/render_view_host_impl.h b/content/browser/renderer_host/render_view_host_impl.h
index af7f7b0..90fabda9 100644
--- a/content/browser/renderer_host/render_view_host_impl.h
+++ b/content/browser/renderer_host/render_view_host_impl.h
@@ -239,7 +239,6 @@
   bool MayRenderWidgetForwardKeyboardEvent(
       const NativeWebKeyboardEvent& key_event) override;
   bool ShouldContributePriorityToProcess() override;
-  void RenderWidgetDidShutdown() override;
 
   // IPC message handlers.
   void OnShowView(int route_id,
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index ff49b4f..d350309 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -611,41 +611,9 @@
   RejectMouseLockOrUnlockIfNecessary();
 
   if (process_->IsInitializedAndNotDead()) {
-    // This logic below simulates the routing behavior from when RenderWidget
-    // associated with RenderViews shared the same routing IDs.
-    //
-    // In the original code, the sharing of the routing ID yielded a bastardized
-    // version of dynamic dispatch wherein the ultimate static code path that
-    // handled a ViewMsg_Close changed based on if
-    //
-    //   (a) the RenderWidgetImpl was also a RenderViewImpl
-    //   (b) the RenderViewImpl hooked the message in OnMessageReceived
-    //
-    // In the current code, if RenderWidgetImpl IS NOT a RenderViewImpl,
-    // RenderWidgetHost WILL NOT have a |owner_delegate_| and the message can
-    // be dispatched directly. This is the simplest case.
-    //
-    // If RenderWidgetImpl IS is a RenderViewImpl, then on some platforms
-    // (seems like only Mac?) RenderViewImpl overrides ViewMsg::OnClose to do
-    // additional processing before passing it up to RenderWidgetImpl::OnClose.
-    //
-    // When it is not overridden, the message delegated up via
-    // IPC_MESSAGE_UNHANDLED to the RenderWidget's message dispatching.
-    //
-    // Basically, there are 2 overlapping hand-written implementations of
-    // dynamic dispatch occuring: one via IPC_MESSAGE_UNHANDLED, and another
-    // via calling the super-class method.
-    //
-    // TODO(ajwong): Once the routing_id split CL lands, remove one of these
-    // implementaions of hand-written dyanmic dispatch. The world does not
-    // need so many implementations of what's effectively "virtual."
-    if (owner_delegate_) {
-      owner_delegate_->RenderWidgetDidShutdown();
-    } else {
-      // Tell the non-view RendererWidget to close.
-      bool rv = Send(new ViewMsg_Close(routing_id_));
-      DCHECK(rv);
-    }
+    // Tell the RendererWidget to close.
+    bool rv = Send(new ViewMsg_Close(routing_id_));
+    DCHECK(rv);
   }
 
   Destroy(also_delete);
diff --git a/content/browser/renderer_host/render_widget_host_owner_delegate.h b/content/browser/renderer_host/render_widget_host_owner_delegate.h
index 24a08a3f..409e8ef 100644
--- a/content/browser/renderer_host/render_widget_host_owner_delegate.h
+++ b/content/browser/renderer_host/render_widget_host_owner_delegate.h
@@ -57,9 +57,6 @@
   // priority to the RenderProcessHost.
   virtual bool ShouldContributePriorityToProcess() = 0;
 
-  // Called when the RenderWidgetHost has shutdown.
-  virtual void RenderWidgetDidShutdown() = 0;
-
  protected:
   virtual ~RenderWidgetHostOwnerDelegate() {}
 };
diff --git a/content/browser/service_worker/embedded_worker_test_helper.cc b/content/browser/service_worker/embedded_worker_test_helper.cc
index 92fcf8b..46da680 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.cc
+++ b/content/browser/service_worker/embedded_worker_test_helper.cc
@@ -266,7 +266,7 @@
 
   void DispatchNotificationClickEvent(
       const std::string& notification_id,
-      const PlatformNotificationData& notification_data,
+      const blink::PlatformNotificationData& notification_data,
       int action_index,
       const base::Optional<base::string16>& reply,
       DispatchNotificationClickEventCallback callback) override {
@@ -279,7 +279,7 @@
 
   void DispatchNotificationCloseEvent(
       const std::string& notification_id,
-      const PlatformNotificationData& notification_data,
+      const blink::PlatformNotificationData& notification_data,
       DispatchNotificationCloseEventCallback callback) override {
     if (!helper_)
       return;
@@ -654,7 +654,7 @@
 
 void EmbeddedWorkerTestHelper::OnNotificationClickEvent(
     const std::string& notification_id,
-    const PlatformNotificationData& notification_data,
+    const blink::PlatformNotificationData& notification_data,
     int action_index,
     const base::Optional<base::string16>& reply,
     mojom::ServiceWorker::DispatchNotificationClickEventCallback callback) {
@@ -664,7 +664,7 @@
 
 void EmbeddedWorkerTestHelper::OnNotificationCloseEvent(
     const std::string& notification_id,
-    const PlatformNotificationData& notification_data,
+    const blink::PlatformNotificationData& notification_data,
     mojom::ServiceWorker::DispatchNotificationCloseEventCallback callback) {
   std::move(callback).Run(blink::mojom::ServiceWorkerEventStatus::COMPLETED,
                           base::Time::Now());
@@ -933,7 +933,7 @@
 
 void EmbeddedWorkerTestHelper::OnNotificationClickEventStub(
     const std::string& notification_id,
-    const PlatformNotificationData& notification_data,
+    const blink::PlatformNotificationData& notification_data,
     int action_index,
     const base::Optional<base::string16>& reply,
     mojom::ServiceWorker::DispatchNotificationClickEventCallback callback) {
@@ -946,7 +946,7 @@
 
 void EmbeddedWorkerTestHelper::OnNotificationCloseEventStub(
     const std::string& notification_id,
-    const PlatformNotificationData& notification_data,
+    const blink::PlatformNotificationData& notification_data,
     mojom::ServiceWorker::DispatchNotificationCloseEventCallback callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
diff --git a/content/browser/service_worker/embedded_worker_test_helper.h b/content/browser/service_worker/embedded_worker_test_helper.h
index 0494310..13f5947 100644
--- a/content/browser/service_worker/embedded_worker_test_helper.h
+++ b/content/browser/service_worker/embedded_worker_test_helper.h
@@ -33,6 +33,10 @@
 
 class GURL;
 
+namespace blink {
+struct PlatformNotificationData;
+}
+
 namespace content {
 
 struct BackgroundFetchRegistration;
@@ -42,7 +46,6 @@
 class ServiceWorkerContextCore;
 class ServiceWorkerContextWrapper;
 class TestBrowserContext;
-struct PlatformNotificationData;
 
 // In-Process EmbeddedWorker test helper.
 //
@@ -196,13 +199,13 @@
       mojom::ServiceWorker::DispatchFetchEventCallback finish_callback);
   virtual void OnNotificationClickEvent(
       const std::string& notification_id,
-      const PlatformNotificationData& notification_data,
+      const blink::PlatformNotificationData& notification_data,
       int action_index,
       const base::Optional<base::string16>& reply,
       mojom::ServiceWorker::DispatchNotificationClickEventCallback callback);
   virtual void OnNotificationCloseEvent(
       const std::string& notification_id,
-      const PlatformNotificationData& notification_data,
+      const blink::PlatformNotificationData& notification_data,
       mojom::ServiceWorker::DispatchNotificationCloseEventCallback callback);
   virtual void OnPushEvent(
       base::Optional<std::string> payload,
@@ -290,13 +293,13 @@
       mojom::ServiceWorker::DispatchFetchEventCallback finish_callback);
   void OnNotificationClickEventStub(
       const std::string& notification_id,
-      const PlatformNotificationData& notification_data,
+      const blink::PlatformNotificationData& notification_data,
       int action_index,
       const base::Optional<base::string16>& reply,
       mojom::ServiceWorker::DispatchNotificationClickEventCallback callback);
   void OnNotificationCloseEventStub(
       const std::string& notification_id,
-      const PlatformNotificationData& notification_data,
+      const blink::PlatformNotificationData& notification_data,
       mojom::ServiceWorker::DispatchNotificationCloseEventCallback callback);
   void OnPushEventStub(
       base::Optional<std::string> payload,
diff --git a/content/browser/service_worker/service_worker_provider_host.cc b/content/browser/service_worker/service_worker_provider_host.cc
index 846f77b2..d8eea1e3 100644
--- a/content/browser/service_worker/service_worker_provider_host.cc
+++ b/content/browser/service_worker/service_worker_provider_host.cc
@@ -43,7 +43,7 @@
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/resource_request_body.h"
 #include "storage/browser/blob/blob_storage_context.h"
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
 #include "third_party/blink/public/common/service_worker/service_worker_utils.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_client.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h"
diff --git a/content/browser/shared_worker/mock_shared_worker.h b/content/browser/shared_worker/mock_shared_worker.h
index 5920e02b0..d9f6f78 100644
--- a/content/browser/shared_worker/mock_shared_worker.h
+++ b/content/browser/shared_worker/mock_shared_worker.h
@@ -17,7 +17,7 @@
 #include "content/common/service_worker/service_worker_provider.mojom.h"
 #include "content/common/shared_worker/shared_worker_factory.mojom.h"
 #include "mojo/public/cpp/bindings/binding.h"
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
 
 class GURL;
 
diff --git a/content/browser/shared_worker/shared_worker_connector_impl.cc b/content/browser/shared_worker/shared_worker_connector_impl.cc
index 2fe70f5..454feba 100644
--- a/content/browser/shared_worker/shared_worker_connector_impl.cc
+++ b/content/browser/shared_worker/shared_worker_connector_impl.cc
@@ -11,7 +11,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/render_process_host.h"
 #include "mojo/public/cpp/bindings/strong_binding.h"
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
 
 namespace content {
 
diff --git a/content/browser/shared_worker/shared_worker_host.cc b/content/browser/shared_worker/shared_worker_host.cc
index 840ad10..7623fb824 100644
--- a/content/browser/shared_worker/shared_worker_host.cc
+++ b/content/browser/shared_worker/shared_worker_host.cc
@@ -27,7 +27,7 @@
 #include "content/public/common/renderer_preference_watcher.mojom.h"
 #include "services/network/public/cpp/features.h"
 #include "third_party/blink/public/common/features.h"
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
 #include "third_party/blink/public/common/service_worker/service_worker_utils.h"
 #include "third_party/blink/public/platform/web_feature.mojom.h"
 #include "third_party/blink/public/web/worker_content_settings_proxy.mojom.h"
@@ -105,6 +105,12 @@
   // AddClient() or Start(). AddClient() can sometimes be called before Start()
   // when two clients call new SharedWorker() at around the same time.
   worker_request_ = mojo::MakeRequest(&worker_);
+
+  // Keep the renderer process alive that will be hosting the shared worker.
+  RenderProcessHost* process_host = RenderProcessHost::FromID(process_id);
+  DCHECK(!IsShuttingDown(process_host));
+  process_host->IncrementKeepAliveRefCount(
+      RenderProcessHost::KeepAliveClientType::kSharedWorker);
 }
 
 SharedWorkerHost::~SharedWorkerHost() {
@@ -124,6 +130,12 @@
     case Phase::kTerminationSentAndClosed:
       break;
   }
+
+  RenderProcessHost* process_host = RenderProcessHost::FromID(process_id_);
+  if (!IsShuttingDown(process_host)) {
+    process_host->DecrementKeepAliveRefCount(
+        RenderProcessHost::KeepAliveClientType::kSharedWorker);
+  }
 }
 
 void SharedWorkerHost::Start(
diff --git a/content/browser/shared_worker/shared_worker_host_unittest.cc b/content/browser/shared_worker/shared_worker_host_unittest.cc
index 638a492..26da664 100644
--- a/content/browser/shared_worker/shared_worker_host_unittest.cc
+++ b/content/browser/shared_worker/shared_worker_host_unittest.cc
@@ -19,13 +19,11 @@
 #include "content/public/test/mock_render_process_host.h"
 #include "content/public/test/test_browser_context.h"
 #include "content/public/test/test_browser_thread_bundle.h"
-#include "content/public/test/test_storage_partition.h"
 #include "content/public/test/test_utils.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/test_support/test_utils.h"
-#include "services/network/test/test_network_context.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
 #include "url/origin.h"
 
 using blink::MessagePortChannel;
@@ -36,11 +34,9 @@
  public:
   SharedWorkerHostTest()
       : mock_render_process_host_(&browser_context_),
-        service_(&storage_partition_,
+        service_(nullptr /* storage_partition */,
                  nullptr /* service_worker_context */,
-                 nullptr /* appcache_service */) {
-    storage_partition_.set_network_context(&network_context_);
-  }
+                 nullptr /* appcache_service */) {}
 
   base::WeakPtr<SharedWorkerHost> CreateHost() {
     GURL url("http://www.example.com/w.js");
@@ -86,8 +82,6 @@
 
  protected:
   TestBrowserThreadBundle test_browser_thread_bundle_;
-  TestStoragePartition storage_partition_;
-  network::TestNetworkContext network_context_;
   TestBrowserContext browser_context_;
   MockRenderProcessHost mock_render_process_host_;
 
diff --git a/content/browser/shared_worker/shared_worker_service_impl.cc b/content/browser/shared_worker/shared_worker_service_impl.cc
index b383daf9..1b61495 100644
--- a/content/browser/shared_worker/shared_worker_service_impl.cc
+++ b/content/browser/shared_worker/shared_worker_service_impl.cc
@@ -42,7 +42,7 @@
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "services/network/loader_util.h"
 #include "services/network/public/cpp/features.h"
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
 #include "third_party/blink/public/common/service_worker/service_worker_utils.h"
 #include "url/origin.h"
 
@@ -56,11 +56,6 @@
                             blink::mojom::SharedWorkerMainScriptLoadParamsPtr,
                             base::Optional<SubresourceLoaderParams>)>;
 
-bool IsShuttingDown(RenderProcessHost* host) {
-  return !host || host->FastShutdownStarted() ||
-         host->IsKeepAliveRefCountDisabled();
-}
-
 std::unique_ptr<URLLoaderFactoryBundleInfo> CreateFactoryBundle(
     int process_id,
     StoragePartitionImpl* storage_partition,
@@ -221,8 +216,13 @@
 
 }  // namespace
 
+bool IsShuttingDown(RenderProcessHost* host) {
+  return !host || host->FastShutdownStarted() ||
+         host->IsKeepAliveRefCountDisabled();
+}
+
 SharedWorkerServiceImpl::SharedWorkerServiceImpl(
-    StoragePartition* storage_partition,
+    StoragePartitionImpl* storage_partition,
     scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
     scoped_refptr<ChromeAppCacheService> appcache_service)
     : storage_partition_(storage_partition),
@@ -261,9 +261,11 @@
                                                   std::move(callback));
   } else {
     terminate_all_workers_callback_ = std::move(callback);
-    for (auto& host : worker_hosts_)
-      host->TerminateWorker();
-    // Monitor for actual termination in DestroyHost.
+    // Use an explicit iterator and be careful because TerminateWorker() can
+    // call DestroyHost(), which removes the host from |worker_hosts_| and could
+    // invalidate the iterator.
+    for (auto it = worker_hosts_.begin(); it != worker_hosts_.end();)
+      (*it++)->TerminateWorker();
   }
 }
 
@@ -331,17 +333,11 @@
 
 void SharedWorkerServiceImpl::DestroyHost(SharedWorkerHost* host) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-  RenderProcessHost* process_host =
-      RenderProcessHost::FromID(host->process_id());
   worker_hosts_.erase(worker_hosts_.find(host));
 
   // Complete the call to TerminateAllWorkersForTesting if no more workers.
   if (worker_hosts_.empty() && terminate_all_workers_callback_)
     std::move(terminate_all_workers_callback_).Run();
-
-  if (!IsShuttingDown(process_host))
-    process_host->DecrementKeepAliveRefCount(
-        RenderProcessHost::KeepAliveClientType::kSharedWorker);
 }
 
 void SharedWorkerServiceImpl::CreateWorker(
@@ -352,7 +348,6 @@
     const blink::MessagePortChannel& message_port,
     scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
-
   DCHECK(!blob_url_loader_factory || instance->url().SchemeIsBlob());
 
   bool constructor_uses_file_url =
@@ -370,22 +365,15 @@
   // Bounce to the IO thread to setup service worker and appcache support in
   // case the request for the worker script will need to be intercepted by them.
   if (blink::ServiceWorkerUtils::IsServicificationEnabled()) {
-    StoragePartitionImpl* storage_partition =
-        service_worker_context_->storage_partition();
-    if (!storage_partition) {
-      // The context is shutting down. Just drop the request.
-      return;
-    }
-
     // Set up the factory bundle for non-NetworkService URLs, e.g.,
     // chrome-extension:// URLs. One factory bundle is consumed by the browser
     // for SharedWorkerScriptLoaderFactory, and one is sent to the renderer for
     // subresource loading.
     std::unique_ptr<URLLoaderFactoryBundleInfo> factory_bundle_for_browser =
-        CreateFactoryBundle(process_id, storage_partition,
+        CreateFactoryBundle(process_id, storage_partition_,
                             constructor_uses_file_url);
     std::unique_ptr<URLLoaderFactoryBundleInfo> subresource_loader_factories =
-        CreateFactoryBundle(process_id, storage_partition,
+        CreateFactoryBundle(process_id, storage_partition_,
                             constructor_uses_file_url);
 
     // NetworkService (PlzWorker):
@@ -433,7 +421,7 @@
         BrowserThread::IO, FROM_HERE,
         base::BindOnce(
             &CreateScriptLoaderOnIO,
-            storage_partition->url_loader_factory_getter(),
+            storage_partition_->url_loader_factory_getter(),
             std::move(factory_bundle_for_browser),
             std::move(subresource_loader_factories), service_worker_context_,
             appcache_handle_core,
@@ -487,10 +475,6 @@
     return;
   }
 
-  // Keep the renderer process alive that will be hosting the shared worker.
-  process_host->IncrementKeepAliveRefCount(
-      RenderProcessHost::KeepAliveClientType::kSharedWorker);
-
   // Get the factory used to instantiate the new shared worker instance in
   // the target process.
   mojom::SharedWorkerFactoryPtr factory;
diff --git a/content/browser/shared_worker/shared_worker_service_impl.h b/content/browser/shared_worker/shared_worker_service_impl.h
index c993eb07..11f0b06b 100644
--- a/content/browser/shared_worker/shared_worker_service_impl.h
+++ b/content/browser/shared_worker/shared_worker_service_impl.h
@@ -33,14 +33,17 @@
 class ChromeAppCacheService;
 class SharedWorkerInstance;
 class SharedWorkerHost;
-class StoragePartition;
+class StoragePartitionImpl;
 struct SubresourceLoaderParams;
 
+// Shared helper function
+bool IsShuttingDown(RenderProcessHost* host);
+
 // Created per StoragePartition.
 class CONTENT_EXPORT SharedWorkerServiceImpl : public SharedWorkerService {
  public:
   SharedWorkerServiceImpl(
-      StoragePartition* storage_partition,
+      StoragePartitionImpl* storage_partition,
       scoped_refptr<ServiceWorkerContextWrapper> service_worker_context,
       scoped_refptr<ChromeAppCacheService> appcache_service);
   ~SharedWorkerServiceImpl() override;
@@ -64,7 +67,7 @@
 
   void DestroyHost(SharedWorkerHost* host);
 
-  StoragePartition* storage_partition() { return storage_partition_; }
+  StoragePartitionImpl* storage_partition() { return storage_partition_; }
 
  private:
   friend class SharedWorkerServiceImplTest;
@@ -102,7 +105,7 @@
   base::OnceClosure terminate_all_workers_callback_;
 
   // |storage_partition_| owns |this|.
-  StoragePartition* const storage_partition_;
+  StoragePartitionImpl* const storage_partition_;
   scoped_refptr<ServiceWorkerContextWrapper> service_worker_context_;
   scoped_refptr<ChromeAppCacheService> appcache_service_;
 
diff --git a/content/browser/shared_worker/shared_worker_service_impl_unittest.cc b/content/browser/shared_worker/shared_worker_service_impl_unittest.cc
index e5d67bd..5f04ca0 100644
--- a/content/browser/shared_worker/shared_worker_service_impl_unittest.cc
+++ b/content/browser/shared_worker/shared_worker_service_impl_unittest.cc
@@ -24,7 +24,7 @@
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "mojo/public/cpp/test_support/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
 
 using blink::MessagePortChannel;
 
diff --git a/content/browser/site_per_process_browsertest.cc b/content/browser/site_per_process_browsertest.cc
index 1497e843..6ce5af5 100644
--- a/content/browser/site_per_process_browsertest.cc
+++ b/content/browser/site_per_process_browsertest.cc
@@ -1836,19 +1836,10 @@
   scroll_observer->Wait();
 }
 
-#if defined(OS_CHROMEOS) || defined(OS_MACOSX)
-// Flaky: https://crbug.com/836200.
-// Flaky timeouts on Mac: https://crbug.com/863971.
-#define MAYBE_ScrollBubblingFromOOPIFWithBodyOverflowHidden \
-  DISABLED_ScrollBubblingFromOOPIFWithBodyOverflowHidden
-#else
-#define MAYBE_ScrollBubblingFromOOPIFWithBodyOverflowHidden \
-  ScrollBubblingFromOOPIFWithBodyOverflowHidden
-#endif
 // Tests that scrolling bubbles from an oopif if its source body has
 // "overflow:hidden" style.
 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
-                       MAYBE_ScrollBubblingFromOOPIFWithBodyOverflowHidden) {
+                       ScrollBubblingFromOOPIFWithBodyOverflowHidden) {
   GURL url_domain_a(embedded_test_server()->GetURL(
       "a.com", "/scrollable_page_with_iframe.html"));
   EXPECT_TRUE(NavigateToURL(shell(), url_domain_a));
diff --git a/content/browser/site_per_process_hit_test_browsertest.cc b/content/browser/site_per_process_hit_test_browsertest.cc
index da022d8..92776ea 100644
--- a/content/browser/site_per_process_hit_test_browsertest.cc
+++ b/content/browser/site_per_process_hit_test_browsertest.cc
@@ -2169,18 +2169,10 @@
   EXPECT_EQ(result.target_location.value(), parent_location);
 }
 
-#if defined(THREAD_SANITIZER) || defined(OS_LINUX)
-// Flaky: https://crbug.com/833380
-#define MAYBE_SurfaceHitTestPointerEventsNone \
-  DISABLED_SurfaceHitTestPointerEventsNone
-#else
-#define MAYBE_SurfaceHitTestPointerEventsNone SurfaceHitTestPointerEventsNone
-#endif
-
 // This test tests that browser process hittesting ignores frames with
 // pointer-events: none.
 IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
-                       MAYBE_SurfaceHitTestPointerEventsNone) {
+                       SurfaceHitTestPointerEventsNone) {
   // TODO(sunxd): Fix pointer-events none for surface layer viz hit testing. See
   // https://crbug.com/841358.
   if (features::IsVizHitTestingSurfaceLayerEnabled()) {
@@ -2235,18 +2227,10 @@
   EXPECT_FALSE(child_frame_monitor.EventWasReceived());
 }
 
-#if defined(OS_CHROMEOS)
-// Flaky on Chrome OS. crbug.com/833380
-#define MAYBE_AsynchronousHitTestChildTimeout \
-  DISABLED_AsynchronousHitTestChildTimeout
-#else
-#define MAYBE_AsynchronousHitTestChildTimeout AsynchronousHitTestChildTimeout
-#endif
-
 // Verify that an event is properly retargeted to the main frame when an
 // asynchronous hit test to the child frame times out.
 IN_PROC_BROWSER_TEST_P(SitePerProcessHitTestBrowserTest,
-                       MAYBE_AsynchronousHitTestChildTimeout) {
+                       AsynchronousHitTestChildTimeout) {
   GURL main_url(embedded_test_server()->GetURL(
       "/frame_tree/page_with_positioned_busy_frame.html"));
   EXPECT_TRUE(NavigateToURL(shell(), main_url));
diff --git a/content/browser/web_package/signed_exchange_handler.cc b/content/browser/web_package/signed_exchange_handler.cc
index 64e39f6..ae86f07 100644
--- a/content/browser/web_package/signed_exchange_handler.cc
+++ b/content/browser/web_package/signed_exchange_handler.cc
@@ -526,6 +526,8 @@
   }
 
   network::ResourceResponseHead response_head;
+  response_head.is_signed_exchange_inner_response = true;
+
   response_head.headers = envelope_->BuildHttpResponseHeaders();
   response_head.headers->GetMimeTypeAndCharset(&response_head.mime_type,
                                                &response_head.charset);
diff --git a/content/browser/web_package/signed_exchange_loader.cc b/content/browser/web_package/signed_exchange_loader.cc
index d03dd7f..7d670395 100644
--- a/content/browser/web_package/signed_exchange_loader.cc
+++ b/content/browser/web_package/signed_exchange_loader.cc
@@ -305,15 +305,15 @@
       !net::IsCertStatusMinorError(ssl_info->cert_status)) {
     ssl_info_ = ssl_info;
   }
+
+  network::ResourceResponseHead inner_response_head_shown_to_client =
+      resource_response;
   if (ssl_info.has_value() &&
       !(url_loader_options_ &
         network::mojom::kURLLoadOptionSendSSLInfoWithResponse)) {
-    network::ResourceResponseHead response_info = resource_response;
-    response_info.ssl_info = base::nullopt;
-    client_->OnReceiveResponse(response_info);
-  } else {
-    client_->OnReceiveResponse(resource_response);
+    inner_response_head_shown_to_client.ssl_info = base::nullopt;
   }
+  client_->OnReceiveResponse(inner_response_head_shown_to_client);
 
   // Currently we always assume that we have body.
   // TODO(https://crbug.com/80374): Add error handling and bail out
diff --git a/content/browser/webrtc/webrtc_audio_browsertest.cc b/content/browser/webrtc/webrtc_audio_browsertest.cc
index 308f749..538577a8b 100644
--- a/content/browser/webrtc/webrtc_audio_browsertest.cc
+++ b/content/browser/webrtc/webrtc_audio_browsertest.cc
@@ -18,73 +18,25 @@
 #include "media/base/media_switches.h"
 #include "media/webrtc/webrtc_switches.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
-#include "services/service_manager/sandbox/features.h"
 #include "testing/gtest/include/gtest/gtest-param-test.h"
 
 namespace content {
 
-namespace {
-
-// Temporary enum, used for running the tests with different combination of
-// flags while audio service is under experiment.
-// TODO(https://crbug.com/850878) Remove after enabling sandboxing on all
-// platforms.
-enum class AudioServiceFeatures {
-  kDisabled,
-  kOutOfProcess,
-#if defined(OS_WIN)
-  kSandboxed,
-#endif
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
-  kSandboxedWithAudioServiceAPM
-#endif
-};
-}  // namespace
-
 // This class tests the scenario when permission to access mic or camera is
 // granted.
-class WebRtcAudioBrowserTest
-    : public WebRtcContentBrowserTestBase,
-      public testing::WithParamInterface<AudioServiceFeatures> {
+class WebRtcAudioBrowserTest : public WebRtcContentBrowserTestBase,
+                               public testing::WithParamInterface<bool> {
  public:
   WebRtcAudioBrowserTest() {
     std::vector<base::Feature> audio_service_oop_features = {
         features::kAudioServiceAudioStreams,
         features::kAudioServiceOutOfProcess};
-    switch (GetParam()) {
-      case AudioServiceFeatures::kDisabled:
-        // Force audio service out of process to disabled.
-        audio_service_features_.InitWithFeatures({},
-                                                 audio_service_oop_features);
-        break;
-      case AudioServiceFeatures::kOutOfProcess:
-        // Force audio service out of process to enabled.
-        audio_service_features_.InitWithFeatures(
-            audio_service_oop_features,
-#if defined(OS_WIN)
-            // Force audio service sandboxing (available only on Windows) to
-            // disabled.
-            {service_manager::features::kAudioServiceSandbox});
-#else
-            {});
-#endif
-        break;
-#if defined(OS_WIN)
-      case AudioServiceFeatures::kSandboxed:
-        // Force audio service out of process and sandboxing to enabled.
-        audio_service_oop_features.push_back(
-            service_manager::features::kAudioServiceSandbox);
-        audio_service_features_.InitWithFeatures(audio_service_oop_features,
-                                                 {});
-        break;
-#endif
-#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX)
-      case AudioServiceFeatures::kSandboxedWithAudioServiceAPM:
-        audio_service_oop_features.push_back(
-            service_manager::features::kAudioServiceSandbox);
-        audio_service_oop_features.push_back(
-            features::kWebRtcApmInAudioService);
-#endif
+    if (GetParam()) {
+      // Force audio service out of process to enabled.
+      audio_service_features_.InitWithFeatures(audio_service_oop_features, {});
+    } else {
+      // Force audio service out of process to disabled.
+      audio_service_features_.InitWithFeatures({}, audio_service_oop_features);
     }
   }
   ~WebRtcAudioBrowserTest() override {}
@@ -178,30 +130,14 @@
 // We run these tests with the audio service both in and out of the the browser
 // process to have waterfall coverage while the feature rolls out. It should be
 // removed after launch.
-#if defined(OS_LINUX) || defined(OS_MACOSX)
+#if defined(OS_LINUX) || defined(OS_MACOSX) || defined(OS_WIN)
 // Supported platforms.
-INSTANTIATE_TEST_CASE_P(
-    ,
-    WebRtcAudioBrowserTest,
-    ::testing::Values(AudioServiceFeatures::kDisabled,
-                      AudioServiceFeatures::kOutOfProcess,
-                      AudioServiceFeatures::kSandboxedWithAudioServiceAPM));
-#elif defined(OS_WIN)
-// On Windows, also run in sandboxed mode.
-INSTANTIATE_TEST_CASE_P(
-    ,
-    WebRtcAudioBrowserTest,
-    ::testing::Values(AudioServiceFeatures::kDisabled,
-                      AudioServiceFeatures::kOutOfProcess,
-                      AudioServiceFeatures::kSandboxed,
-                      AudioServiceFeatures::kSandboxedWithAudioServiceAPM));
+INSTANTIATE_TEST_CASE_P(, WebRtcAudioBrowserTest, ::testing::Bool());
 #elif defined(OS_ANDROID) && defined(ADDRESS_SANITIZER)
 // Renderer crashes under Android ASAN: https://crbug.com/408496.
 #else
 // Platforms where the out of process audio service isn't supported
-INSTANTIATE_TEST_CASE_P(,
-                        WebRtcAudioBrowserTest,
-                        ::testing::Values(AudioServiceFeatures::kDisabled));
+INSTANTIATE_TEST_CASE_P(, WebRtcAudioBrowserTest, ::testing::Values(false));
 #endif
 
 }  // namespace content
diff --git a/content/browser/webrtc/webrtc_getusermedia_browsertest.cc b/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
index 5a997c3d..ed69f7f 100644
--- a/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
+++ b/content/browser/webrtc/webrtc_getusermedia_browsertest.cc
@@ -34,7 +34,6 @@
 
 #if defined(OS_WIN)
 #include "base/win/windows_version.h"
-#include "services/service_manager/sandbox/features.h"
 #endif
 
 namespace {
@@ -58,18 +57,6 @@
 // Results returned by JS.
 static const char kOK[] = "OK";
 
-// Temporary enum, used for running the tests with different combination of
-// flags while audio service is under experiment.
-// TODO(https://crbug.com/850878) Remove after enabling sandboxing on all
-// platforms.
-enum class AudioServiceFeatures {
-  kDisabled,
-  kOutOfProcess,
-#if defined(OS_WIN)
-  kSandboxed,
-#endif
-};
-
 std::string GenerateGetUserMediaWithMandatorySourceID(
     const std::string& function_name,
     const std::string& audio_source_id,
@@ -115,9 +102,8 @@
 
 namespace content {
 
-class WebRtcGetUserMediaBrowserTest
-    : public WebRtcContentBrowserTestBase,
-      public testing::WithParamInterface<AudioServiceFeatures> {
+class WebRtcGetUserMediaBrowserTest : public WebRtcContentBrowserTestBase,
+                                      public testing::WithParamInterface<bool> {
  public:
   WebRtcGetUserMediaBrowserTest() {
     // Automatically grant device permission.
@@ -125,33 +111,12 @@
     std::vector<base::Feature> audio_service_oop_features = {
         features::kAudioServiceAudioStreams,
         features::kAudioServiceOutOfProcess};
-    switch (GetParam()) {
-      case AudioServiceFeatures::kDisabled:
-        // Force audio service out of process to disabled.
-        audio_service_features_.InitWithFeatures({},
-                                                 audio_service_oop_features);
-        break;
-      case AudioServiceFeatures::kOutOfProcess:
-        // Force audio service out of process to enabled.
-        audio_service_features_.InitWithFeatures(
-            audio_service_oop_features,
-#if defined(OS_WIN)
-            // Force audio service sandboxing (available only on Windows) to
-            // disabled.
-            {service_manager::features::kAudioServiceSandbox});
-#else
-            {});
-#endif
-        break;
-#if defined(OS_WIN)
-      case AudioServiceFeatures::kSandboxed:
-        // Force audio service out of process and sandboxing to enabled.
-        audio_service_oop_features.push_back(
-            service_manager::features::kAudioServiceSandbox);
-        audio_service_features_.InitWithFeatures(audio_service_oop_features,
-                                                 {});
-        break;
-#endif
+    if (GetParam()) {
+      // Force audio service out of process to enabled.
+      audio_service_features_.InitWithFeatures(audio_service_oop_features, {});
+    } else {
+      // Force audio service out of process to disabled.
+      audio_service_features_.InitWithFeatures({}, audio_service_oop_features);
     }
   }
   ~WebRtcGetUserMediaBrowserTest() override {}
@@ -825,7 +790,7 @@
                        GetAudioStreamAndCheckMutingInitiallyUnmuted) {
   // Muting tests do not work with the out-of-process audio service.
   // https://crbug.com/843490.
-  if (GetParam() != AudioServiceFeatures::kDisabled)
+  if (GetParam())
     return;
 
   ASSERT_TRUE(embedded_test_server()->Start());
@@ -854,7 +819,7 @@
                        GetAudioStreamAndCheckMutingInitiallyMuted) {
   // Muting tests do not work with the out-of-process audio service.
   // https://crbug.com/843490.
-  if (GetParam() != AudioServiceFeatures::kDisabled)
+  if (GetParam())
     return;
 
   ASSERT_TRUE(embedded_test_server()->Start());
@@ -884,7 +849,7 @@
                        RecoverFromCrashInAudioService) {
   // This test only makes sense with the audio service running out of process,
   // with or without sandbox.
-  if (GetParam() == AudioServiceFeatures::kDisabled)
+  if (!GetParam())
     return;
 
   ASSERT_TRUE(embedded_test_server()->Start());
@@ -907,24 +872,15 @@
 // We run these tests with the audio service both in and out of the the browser
 // process to have waterfall coverage while the feature rolls out. It should be
 // removed after launch.
-#if (defined(OS_LINUX) && !defined(CHROME_OS)) || defined(OS_MACOSX)
+#if (defined(OS_LINUX) && !defined(CHROME_OS)) || defined(OS_MACOSX) || \
+    defined(OS_WIN)
 // Supported platforms.
-INSTANTIATE_TEST_CASE_P(,
-                        WebRtcGetUserMediaBrowserTest,
-                        ::testing::Values(AudioServiceFeatures::kDisabled,
-                                          AudioServiceFeatures::kOutOfProcess));
-#elif defined(OS_WIN)
-// On Windows, also run in sandboxed mode.
-INSTANTIATE_TEST_CASE_P(,
-                        WebRtcGetUserMediaBrowserTest,
-                        ::testing::Values(AudioServiceFeatures::kDisabled,
-                                          AudioServiceFeatures::kOutOfProcess,
-                                          AudioServiceFeatures::kSandboxed));
+INSTANTIATE_TEST_CASE_P(, WebRtcGetUserMediaBrowserTest, ::testing::Bool());
 #else
 // Platforms where the out of process audio service is not supported
 INSTANTIATE_TEST_CASE_P(,
                         WebRtcGetUserMediaBrowserTest,
-                        ::testing::Values(AudioServiceFeatures::kDisabled));
+                        ::testing::Values(false));
 #endif
 
 }  // namespace content
diff --git a/content/child/child_process_sandbox_support_impl_linux.cc b/content/child/child_process_sandbox_support_impl_linux.cc
index 9dd008c8..09db3cc3 100644
--- a/content/child/child_process_sandbox_support_impl_linux.cc
+++ b/content/child/child_process_sandbox_support_impl_linux.cc
@@ -21,7 +21,7 @@
 #include "content/public/common/common_sandbox_support_linux.h"
 #include "services/service_manager/sandbox/linux/sandbox_linux.h"
 #include "services/service_manager/zygote/common/common_sandbox_support_linux.h"
-#include "third_party/blink/public/platform/linux/web_fallback_font.h"
+#include "third_party/blink/public/platform/linux/out_of_process_font.h"
 #include "third_party/blink/public/platform/web_font_render_style.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_vector.h"
@@ -31,7 +31,7 @@
 void GetFallbackFontForCharacter(sk_sp<font_service::FontLoader> font_loader,
                                  int32_t character,
                                  const char* preferred_locale,
-                                 blink::WebFallbackFont* fallback_font) {
+                                 blink::OutOfProcessFont* fallback_font) {
   DCHECK(font_loader.get());
   font_service::mojom::FontIdentityPtr font_identity;
   bool is_bold = false;
@@ -44,7 +44,7 @@
     return;
   }
 
-  // TODO(drott): Perhaps take WebFallbackFont out of the picture here and pass
+  // TODO(drott): Perhaps take OutOfProcessFont out of the picture here and pass
   // mojo FontIdentityPtr directly?
   fallback_font->name =
       blink::WebString::FromUTF8(family_name.c_str(), family_name.length());
diff --git a/content/child/child_process_sandbox_support_impl_linux.h b/content/child/child_process_sandbox_support_impl_linux.h
index 140060c..a73b6d6b 100644
--- a/content/child/child_process_sandbox_support_impl_linux.h
+++ b/content/child/child_process_sandbox_support_impl_linux.h
@@ -11,7 +11,7 @@
 #include "third_party/skia/include/core/SkRefCnt.h"
 
 namespace blink {
-struct WebFallbackFont;
+struct OutOfProcessFont;
 struct WebFontRenderStyle;
 }
 
@@ -24,7 +24,7 @@
 void GetFallbackFontForCharacter(sk_sp<font_service::FontLoader> font_loader,
                                  const int32_t character,
                                  const char* preferred_locale,
-                                 blink::WebFallbackFont* family);
+                                 blink::OutOfProcessFont* family);
 
 // Returns rendering settings for a provided font family, size, and style.
 // |size_and_style| stores the bold setting in its least-significant bit, the
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 1940f0d9..2be103b 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -209,8 +209,6 @@
     "net/url_request_service_worker_data.h",
     "net/url_request_user_data.cc",
     "net/url_request_user_data.h",
-    "notifications/notification_struct_traits.cc",
-    "notifications/notification_struct_traits.h",
     "origin_util.cc",
     "page_messages.h",
     "page_state_serialization.cc",
diff --git a/content/common/content_param_traits.cc b/content/common/content_param_traits.cc
index 59f0865a..1fe5895 100644
--- a/content/common/content_param_traits.cc
+++ b/content/common/content_param_traits.cc
@@ -16,9 +16,9 @@
 #include "ipc/ipc_mojo_message_helper.h"
 #include "ipc/ipc_mojo_param_traits.h"
 #include "net/base/ip_endpoint.h"
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
-#include "third_party/blink/public/common/message_port/transferable_message.h"
-#include "third_party/blink/public/mojom/message_port/message_port.mojom.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
+#include "third_party/blink/public/common/messaging/transferable_message.h"
+#include "third_party/blink/public/mojom/messaging/message_port.mojom.h"
 #include "ui/accessibility/ax_mode.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/events/blink/web_input_event_traits.h"
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index c42a881..0986f4e3 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -59,8 +59,8 @@
 #include "third_party/blink/public/common/feature_policy/feature_policy.h"
 #include "third_party/blink/public/common/frame/frame_policy.h"
 #include "third_party/blink/public/common/frame/user_activation_update_type.h"
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
-#include "third_party/blink/public/common/message_port/transferable_message.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
+#include "third_party/blink/public/common/messaging/transferable_message.h"
 #include "third_party/blink/public/platform/web_focus_type.h"
 #include "third_party/blink/public/platform/web_insecure_request_policy.h"
 #include "third_party/blink/public/platform/web_intrinsic_sizing_info.h"
diff --git a/content/common/notifications/DEPS b/content/common/notifications/DEPS
deleted file mode 100644
index 3855191..0000000
--- a/content/common/notifications/DEPS
+++ /dev/null
@@ -1,3 +0,0 @@
-include_rules = [
-  "+third_party/blink/public/platform/modules/notifications/notification.mojom.h",
-]
diff --git a/content/common/notifications/notification_struct_traits.h b/content/common/notifications/notification_struct_traits.h
deleted file mode 100644
index bf2fccb..0000000
--- a/content/common/notifications/notification_struct_traits.h
+++ /dev/null
@@ -1,182 +0,0 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_COMMON_NOTIFICATIONS_NOTIFICATION_STRUCT_TRAITS_H_
-#define CONTENT_COMMON_NOTIFICATIONS_NOTIFICATION_STRUCT_TRAITS_H_
-
-#include "base/containers/span.h"
-#include "base/strings/string16.h"
-#include "content/common/content_export.h"
-#include "content/public/common/platform_notification_data.h"
-#include "mojo/public/cpp/base/string16_mojom_traits.h"
-#include "mojo/public/cpp/bindings/struct_traits.h"
-#include "skia/public/interfaces/bitmap_skbitmap_struct_traits.h"
-#include "third_party/blink/public/platform/modules/notifications/notification.mojom.h"
-#include "url/gurl.h"
-#include "url/mojom/url_gurl_mojom_traits.h"
-
-namespace mojo {
-
-template <>
-struct CONTENT_EXPORT EnumTraits<blink::mojom::NotificationDirection,
-                                 content::PlatformNotificationData::Direction> {
-  static blink::mojom::NotificationDirection ToMojom(
-      content::PlatformNotificationData::Direction input);
-
-  static bool FromMojom(blink::mojom::NotificationDirection input,
-                        content::PlatformNotificationData::Direction* out);
-};
-
-template <>
-struct CONTENT_EXPORT EnumTraits<blink::mojom::NotificationActionType,
-                                 content::PlatformNotificationActionType> {
-  static blink::mojom::NotificationActionType ToMojom(
-      content::PlatformNotificationActionType input);
-
-  static bool FromMojom(blink::mojom::NotificationActionType input,
-                        content::PlatformNotificationActionType* out);
-};
-
-template <>
-struct CONTENT_EXPORT StructTraits<blink::mojom::NotificationActionDataView,
-                                   content::PlatformNotificationAction> {
-  static content::PlatformNotificationActionType type(
-      const content::PlatformNotificationAction& action) {
-    return action.type;
-  }
-
-  static const std::string& action(
-      const content::PlatformNotificationAction& action) {
-    return action.action;
-  }
-
-  static const base::string16& title(
-      const content::PlatformNotificationAction& action) {
-    return action.title;
-  }
-
-  static const GURL& icon(const content::PlatformNotificationAction& action) {
-    return action.icon;
-  }
-
-  static const base::Optional<base::string16>& placeholder(
-      const content::PlatformNotificationAction& action) {
-    return action.placeholder.as_optional_string16();
-  }
-
-  static bool Read(
-      blink::mojom::NotificationActionDataView notification_action,
-      content::PlatformNotificationAction* platform_notification_action);
-};
-
-template <>
-struct CONTENT_EXPORT StructTraits<blink::mojom::NotificationDataDataView,
-                                   content::PlatformNotificationData> {
-  static const base::string16& title(
-      const content::PlatformNotificationData& data) {
-    return data.title;
-  }
-
-  static content::PlatformNotificationData::Direction direction(
-      const content::PlatformNotificationData& data) {
-    return data.direction;
-  }
-
-  static const std::string& lang(
-      const content::PlatformNotificationData& data) {
-    return data.lang;
-  }
-
-  static const base::string16& body(
-      const content::PlatformNotificationData& data) {
-    return data.body;
-  }
-
-  static const std::string& tag(const content::PlatformNotificationData& data) {
-    return data.tag;
-  }
-
-  static const GURL& image(const content::PlatformNotificationData& data) {
-    return data.image;
-  }
-
-  static const GURL& icon(const content::PlatformNotificationData& data) {
-    return data.icon;
-  }
-
-  static const GURL& badge(const content::PlatformNotificationData& data) {
-    return data.badge;
-  }
-
-  static const base::span<const int32_t> vibration_pattern(
-      const content::PlatformNotificationData& data) {
-    // TODO(https://crbug.com/798466): Store as int32s to avoid this cast.
-    return base::make_span(
-        reinterpret_cast<const int32_t*>(data.vibration_pattern.data()),
-        data.vibration_pattern.size());
-  }
-
-  static double timestamp(const content::PlatformNotificationData& data) {
-    return data.timestamp.ToJsTime();
-  }
-
-  static bool renotify(const content::PlatformNotificationData& data) {
-    return data.renotify;
-  }
-
-  static bool silent(const content::PlatformNotificationData& data) {
-    return data.silent;
-  }
-
-  static bool require_interaction(
-      const content::PlatformNotificationData& data) {
-    return data.require_interaction;
-  }
-
-  static const base::span<const uint8_t> data(
-      const content::PlatformNotificationData& data) {
-    // TODO(https://crbug.com/798466): Align data types to avoid this cast.
-    return base::make_span(reinterpret_cast<const uint8_t*>(data.data.data()),
-                           data.data.size());
-  }
-
-  static const std::vector<content::PlatformNotificationAction>& actions(
-      const content::PlatformNotificationData& data) {
-    return data.actions;
-  }
-
-  static bool Read(
-      blink::mojom::NotificationDataDataView notification_data,
-      content::PlatformNotificationData* platform_notification_data);
-};
-
-template <>
-struct CONTENT_EXPORT StructTraits<blink::mojom::NotificationResourcesDataView,
-                                   content::NotificationResources> {
-  static const SkBitmap& image(
-      const content::NotificationResources& resources) {
-    return resources.image;
-  }
-
-  static const SkBitmap& icon(const content::NotificationResources& resources) {
-    return resources.notification_icon;
-  }
-
-  static const SkBitmap& badge(
-      const content::NotificationResources& resources) {
-    return resources.badge;
-  }
-
-  static const std::vector<SkBitmap>& action_icons(
-      const content::NotificationResources& resources) {
-    return resources.action_icons;
-  }
-
-  static bool Read(blink::mojom::NotificationResourcesDataView in,
-                   content::NotificationResources* out);
-};
-
-}  // namespace mojo
-
-#endif  // CONTENT_BROWSER_NOTIFICATIONS_NOTIFICATION_STRUCT_TRAITS_H_
diff --git a/content/common/notifications/notification_types.typemap b/content/common/notifications/notification_types.typemap
deleted file mode 100644
index f961616..0000000
--- a/content/common/notifications/notification_types.typemap
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//third_party/blink/public/platform/modules/notifications/notification.mojom"
-public_headers = [
-  "//content/public/common/notification_resources.h",
-  "//content/public/common/platform_notification_data.h",
-]
-traits_headers =
-    [ "//content/common/notifications/notification_struct_traits.h" ]
-deps = [
-  "//mojo/public/cpp/bindings",
-  "//third_party/blink/public:blink_headers",
-]
-type_mappings = [
-  "blink.mojom.NotificationData=content::PlatformNotificationData",
-  "blink.mojom.NotificationDirection=content::PlatformNotificationData::Direction",
-  "blink.mojom.NotificationResources=content::NotificationResources",
-]
diff --git a/content/common/service_worker/service_worker.mojom b/content/common/service_worker/service_worker.mojom
index a764a602..f1b0c4d 100644
--- a/content/common/service_worker/service_worker.mojom
+++ b/content/common/service_worker/service_worker.mojom
@@ -8,7 +8,8 @@
 import "mojo/public/mojom/base/time.mojom";
 import "services/network/public/mojom/cookie_manager.mojom";
 import "third_party/blink/public/mojom/fetch/fetch_api_response.mojom";
-import "third_party/blink/public/mojom/message_port/message_port.mojom";
+import "third_party/blink/public/mojom/messaging/message_port.mojom";
+import "third_party/blink/public/mojom/notifications/notification.mojom";
 import "third_party/blink/public/mojom/payments/payment_app.mojom";
 import "third_party/blink/public/mojom/service_worker/dispatch_fetch_event_params.mojom";
 import "third_party/blink/public/mojom/service_worker/service_worker.mojom";
@@ -18,7 +19,6 @@
 import "third_party/blink/public/mojom/service_worker/service_worker_object.mojom";
 import "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom";
 import "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom";
-import "third_party/blink/public/platform/modules/notifications/notification.mojom";
 import "url/mojom/origin.mojom";
 import "url/mojom/url.mojom";
 
diff --git a/content/common/service_worker/service_worker_container.mojom b/content/common/service_worker/service_worker_container.mojom
index b8d4e2f..040ae784 100644
--- a/content/common/service_worker/service_worker_container.mojom
+++ b/content/common/service_worker/service_worker_container.mojom
@@ -6,7 +6,7 @@
 
 import "content/common/service_worker/controller_service_worker.mojom";
 import "mojo/public/mojom/base/string16.mojom";
-import "third_party/blink/public/mojom/message_port/message_port.mojom";
+import "third_party/blink/public/mojom/messaging/message_port.mojom";
 import "third_party/blink/public/mojom/service_worker/service_worker_error_type.mojom";
 import "third_party/blink/public/mojom/service_worker/service_worker_object.mojom";
 import "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom";
diff --git a/content/common/typemaps.gni b/content/common/typemaps.gni
index e78dd1b..a9818ee 100644
--- a/content/common/typemaps.gni
+++ b/content/common/typemaps.gni
@@ -12,7 +12,6 @@
   "//content/common/native_types.typemap",
   "//content/common/native_types_mac.typemap",
   "//content/common/navigation_params.typemap",
-  "//content/common/notifications/notification_types.typemap",
   "//content/common/push_messaging.typemap",
   "//content/common/render_frame_metadata.typemap",
   "//content/common/service_worker/service_worker_fetch_request.typemap",
diff --git a/content/common/view_messages.h b/content/common/view_messages.h
index cb6ce7b..2b458cf 100644
--- a/content/common/view_messages.h
+++ b/content/common/view_messages.h
@@ -243,7 +243,7 @@
 IPC_MESSAGE_ROUTED1(ViewMsg_UpdateWebPreferences,
                     content::WebPreferences)
 
-// Tells the render view to close.
+// Tells the render widget to close.
 // Expects a Close_ACK message when finished.
 IPC_MESSAGE_ROUTED0(ViewMsg_Close)
 
@@ -456,7 +456,7 @@
 // and the browser may ignore this message.
 IPC_MESSAGE_ROUTED1(ViewHostMsg_RequestSetBounds, gfx::Rect /* bounds */)
 
-// Indicates that the render view has been closed in response to a
+// Indicates that the render widget has been closed in response to a
 // Close message.
 IPC_MESSAGE_CONTROL1(ViewHostMsg_Close_ACK,
                      int /* old_route_id */)
diff --git a/content/gpu/gpu_sandbox_hook_linux.cc b/content/gpu/gpu_sandbox_hook_linux.cc
index 4806a3f..306c25d 100644
--- a/content/gpu/gpu_sandbox_hook_linux.cc
+++ b/content/gpu/gpu_sandbox_hook_linux.cc
@@ -237,9 +237,14 @@
     }
   }
 
-  if (UseChromecastSandboxWhitelist() && IsArchitectureArm()) {
-    AddChromecastArmGpuWhitelist(&permissions);
-    return permissions;
+  if (UseChromecastSandboxWhitelist()) {
+    if (UseV4L2Codec())
+      AddV4L2GpuWhitelist(&permissions, options);
+
+    if (IsArchitectureArm()) {
+      AddChromecastArmGpuWhitelist(&permissions);
+      return permissions;
+    }
   }
 
   AddStandardGpuWhiteList(&permissions);
diff --git a/content/ppapi_plugin/ppapi_blink_platform_impl.cc b/content/ppapi_plugin/ppapi_blink_platform_impl.cc
index c88de7f..a81cd24 100644
--- a/content/ppapi_plugin/ppapi_blink_platform_impl.cc
+++ b/content/ppapi_plugin/ppapi_blink_platform_impl.cc
@@ -22,7 +22,7 @@
 #include "third_party/blink/public/platform/mac/web_sandbox_support.h"
 #elif defined(OS_POSIX) && !defined(OS_ANDROID)
 #include "content/child/child_process_sandbox_support_impl_linux.h"
-#include "third_party/blink/public/platform/linux/web_fallback_font.h"
+#include "third_party/blink/public/platform/linux/out_of_process_font.h"
 #include "third_party/blink/public/platform/linux/web_sandbox_support.h"
 #include "third_party/icu/source/common/unicode/utf16.h"
 #endif
@@ -53,7 +53,7 @@
   void GetFallbackFontForCharacter(
       WebUChar32 character,
       const char* preferred_locale,
-      blink::WebFallbackFont* fallbackFont) override;
+      blink::OutOfProcessFont* fallbackFont) override;
   void GetWebFontRenderStyleForStrike(const char* family,
                                       int size,
                                       bool is_bold,
@@ -65,7 +65,7 @@
   // WebKit likes to ask us for the correct font family to use for a set of
   // unicode code points. It needs this information frequently so we cache it
   // here.
-  std::map<int32_t, blink::WebFallbackFont> unicode_font_families_;
+  std::map<int32_t, blink::OutOfProcessFont> unicode_font_families_;
   sk_sp<font_service::FontLoader> font_loader_;
   // For debugging https://crbug.com/312965
   base::SequenceCheckerImpl creation_thread_sequence_checker_;
@@ -91,11 +91,11 @@
 void PpapiBlinkPlatformImpl::SandboxSupport::GetFallbackFontForCharacter(
     WebUChar32 character,
     const char* preferred_locale,
-    blink::WebFallbackFont* fallbackFont) {
+    blink::OutOfProcessFont* fallbackFont) {
   ppapi::ProxyLock::AssertAcquired();
   // For debugging crbug.com/312965
   CHECK(creation_thread_sequence_checker_.CalledOnValidSequence());
-  const std::map<int32_t, blink::WebFallbackFont>::const_iterator iter =
+  const std::map<int32_t, blink::OutOfProcessFont>::const_iterator iter =
       unicode_font_families_.find(character);
   if (iter != unicode_font_families_.end()) {
     fallbackFont->name = iter->second.name;
@@ -145,7 +145,7 @@
 
 void PpapiBlinkPlatformImpl::Shutdown() {
 #if !defined(OS_ANDROID) && !defined(OS_WIN)
-  // SandboxSupport contains a map of WebFallbackFont objects, which hold
+  // SandboxSupport contains a map of OutOfProcessFont objects, which hold
   // WebStrings and WebVectors, which become invalidated when blink is shut
   // down. Hence, we need to clear that map now, just before blink::shutdown()
   // is called.
diff --git a/content/public/android/java/src/org/chromium/content/browser/MotionEventSynthesizerImpl.java b/content/public/android/java/src/org/chromium/content/browser/MotionEventSynthesizerImpl.java
index 734618c..b277fa0 100644
--- a/content/public/android/java/src/org/chromium/content/browser/MotionEventSynthesizerImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/MotionEventSynthesizerImpl.java
@@ -4,6 +4,7 @@
 
 package org.chromium.content.browser;
 
+import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.MotionEvent.PointerCoords;
 import android.view.MotionEvent.PointerProperties;
@@ -179,7 +180,8 @@
         if (MotionEventAction.HOVER_EXIT == action) androidAction = MotionEvent.ACTION_HOVER_EXIT;
         if (MotionEventAction.HOVER_MOVE == action) androidAction = MotionEvent.ACTION_HOVER_MOVE;
         MotionEvent event = MotionEvent.obtain(mDownTimeInMs, timeInMs, androidAction, pointerCount,
-                mPointerProperties, mPointerCoords, 0, 0, 1, 1, 0, 0, 0, 0);
+                mPointerProperties, mPointerCoords, 0, 0, 1, 1, 0, 0,
+                InputDevice.SOURCE_CLASS_POINTER, 0);
         mTarget.dispatchGenericMotionEvent(event);
         event.recycle();
     }
diff --git a/content/public/browser/BUILD.gn b/content/public/browser/BUILD.gn
index ed1ba21..9553338 100644
--- a/content/public/browser/BUILD.gn
+++ b/content/public/browser/BUILD.gn
@@ -102,6 +102,7 @@
     "content_browser_client.h",
     "context_factory.h",
     "cookie_store_factory.h",
+    "delegate_to_browser_gpu_service_accelerator_factory.h",
     "desktop_capture.cc",
     "desktop_capture.h",
     "desktop_media_id.cc",
diff --git a/content/public/browser/DEPS b/content/public/browser/DEPS
index 4089724..17dc313 100644
--- a/content/public/browser/DEPS
+++ b/content/public/browser/DEPS
@@ -11,6 +11,7 @@
   "+services/network/public/cpp",
   "+services/service_manager/sandbox",
   "+services/resource_coordinator/public",
+  "+services/video_capture/public/mojom",
   "+services/ws/public/mojom",
 ]
 
diff --git a/content/public/browser/delegate_to_browser_gpu_service_accelerator_factory.h b/content/public/browser/delegate_to_browser_gpu_service_accelerator_factory.h
new file mode 100644
index 0000000..0e8b5f8
--- /dev/null
+++ b/content/public/browser/delegate_to_browser_gpu_service_accelerator_factory.h
@@ -0,0 +1,25 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_BROWSER_DELEGATE_TO_BROWSER_GPU_SERVICE_ACCELERATOR_FACTORY_H_
+#define CONTENT_PUBLIC_BROWSER_DELEGATE_TO_BROWSER_GPU_SERVICE_ACCELERATOR_FACTORY_H_
+
+#include "content/common/content_export.h"
+#include "services/video_capture/public/mojom/device_factory_provider.mojom.h"
+
+namespace content {
+
+// Implementation of video_capture::mojom::AcceleratorFactor that satisfies
+// requests for a JpegDecodeAccelerator by delegating to the global instance of
+// viz::mojom::GpuService that is accessible from the Browser process.
+class CONTENT_EXPORT DelegateToBrowserGpuServiceAcceleratorFactory
+    : public video_capture::mojom::AcceleratorFactory {
+ public:
+  void CreateJpegDecodeAccelerator(
+      media::mojom::JpegDecodeAcceleratorRequest jda_request) override;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_BROWSER_DELEGATE_TO_BROWSER_GPU_SERVICE_ACCELERATOR_FACTORY_H_
diff --git a/content/public/browser/gpu_service_registry.cc b/content/public/browser/gpu_service_registry.cc
index 97ab27d..e326a294 100644
--- a/content/public/browser/gpu_service_registry.cc
+++ b/content/public/browser/gpu_service_registry.cc
@@ -4,13 +4,14 @@
 
 #include "content/public/browser/gpu_service_registry.h"
 
+#include "components/viz/host/gpu_host_impl.h"
 #include "content/browser/gpu/gpu_process_host.h"
 
 namespace content {
 
 void BindInterfaceInGpuProcess(const std::string& interface_name,
                                mojo::ScopedMessagePipeHandle interface_pipe) {
-  GpuProcessHost* host = GpuProcessHost::Get();
+  auto* host = GpuProcessHost::Get()->gpu_host();
   return host->BindInterface(interface_name, std::move(interface_pipe));
 }
 
diff --git a/content/public/browser/notification_database_data.h b/content/public/browser/notification_database_data.h
index 0f8744d..d5823b1 100644
--- a/content/public/browser/notification_database_data.h
+++ b/content/public/browser/notification_database_data.h
@@ -11,7 +11,7 @@
 #include "base/optional.h"
 #include "base/time/time.h"
 #include "content/common/content_export.h"
-#include "content/public/common/platform_notification_data.h"
+#include "third_party/blink/public/common/notifications/platform_notification_data.h"
 #include "url/gurl.h"
 
 namespace content {
@@ -51,7 +51,7 @@
   int64_t service_worker_registration_id = 0;
 
   // Platform data of the notification that's being stored.
-  PlatformNotificationData notification_data;
+  blink::PlatformNotificationData notification_data;
 
   // Boolean for if this current notification is replacing an existing
   // notification.
diff --git a/content/public/browser/platform_notification_service.h b/content/public/browser/platform_notification_service.h
index 0e9ce43..80ffd8d 100644
--- a/content/public/browser/platform_notification_service.h
+++ b/content/public/browser/platform_notification_service.h
@@ -19,11 +19,14 @@
 
 class GURL;
 
+namespace blink {
+struct NotificationResources;
+struct PlatformNotificationData;
+}  // namespace blink
+
 namespace content {
 
 class BrowserContext;
-struct NotificationResources;
-struct PlatformNotificationData;
 
 // The service using which notifications can be presented to the user. There
 // should be a unique instance of the PlatformNotificationService depending
@@ -42,8 +45,8 @@
       BrowserContext* browser_context,
       const std::string& notification_id,
       const GURL& origin,
-      const PlatformNotificationData& notification_data,
-      const NotificationResources& notification_resources) = 0;
+      const blink::PlatformNotificationData& notification_data,
+      const blink::NotificationResources& notification_resources) = 0;
 
   // Displays the persistent notification described in |notification_data| to
   // the user. This method must be called on the UI thread.
@@ -52,8 +55,8 @@
       const std::string& notification_id,
       const GURL& service_worker_origin,
       const GURL& origin,
-      const PlatformNotificationData& notification_data,
-      const NotificationResources& notification_resources) = 0;
+      const blink::PlatformNotificationData& notification_data,
+      const blink::NotificationResources& notification_resources) = 0;
 
   // Closes the notification identified by |notification_id|. This method must
   // be called on the UI thread.
diff --git a/content/public/common/BUILD.gn b/content/public/common/BUILD.gn
index f042611..3b0dba3 100644
--- a/content/public/common/BUILD.gn
+++ b/content/public/common/BUILD.gn
@@ -173,8 +173,6 @@
     "mhtml_generation_params.h",
     "mime_handler_view_mode.cc",
     "mime_handler_view_mode.h",
-    "notification_resources.cc",
-    "notification_resources.h",
     "origin_util.h",
     "page_importance_signals.h",
     "page_state.cc",
@@ -184,8 +182,6 @@
     "pepper_plugin_info.cc",
     "pepper_plugin_info.h",
     "persistent_notification_status.h",
-    "platform_notification_data.cc",
-    "platform_notification_data.h",
     "previews_state.h",
     "process_type.h",
     "push_subscription_options.h",
diff --git a/content/renderer/loader/url_loader_client_impl.cc b/content/renderer/loader/url_loader_client_impl.cc
index bffdb0a..9b09fa6 100644
--- a/content/renderer/loader/url_loader_client_impl.cc
+++ b/content/renderer/loader/url_loader_client_impl.cc
@@ -285,7 +285,7 @@
 }
 
 void URLLoaderClientImpl::OnTransferSizeUpdated(int32_t transfer_size_diff) {
-  if (is_deferred_) {
+  if (NeedsStoringMessage()) {
     accumulated_transfer_size_diff_during_deferred_ += transfer_size_diff;
   } else {
     resource_dispatcher_->OnTransferSizeUpdated(request_id_,
@@ -307,7 +307,7 @@
   body_consumer_ = new URLResponseBodyConsumer(
       request_id_, resource_dispatcher_, std::move(body), task_runner_);
 
-  if (is_deferred_) {
+  if (NeedsStoringMessage()) {
     body_consumer_->SetDefersLoading();
     return;
   }
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc
index 615fca5c..d32ccda 100644
--- a/content/renderer/loader/web_url_loader_impl.cc
+++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -1205,6 +1205,8 @@
   response->SetConnectionInfo(info.connection_info);
   response->SetAsyncRevalidationRequested(info.async_revalidation_requested);
   response->SetRequestId(request_id);
+  response->SetIsSignedExchangeInnerResponse(
+      info.is_signed_exchange_inner_response);
 
   SetSecurityStyleAndDetails(url, info, response, report_security_info);
 
diff --git a/content/renderer/media/stream/media_stream_audio_processor.cc b/content/renderer/media/stream/media_stream_audio_processor.cc
index 47f2533..72fe240 100644
--- a/content/renderer/media/stream/media_stream_audio_processor.cc
+++ b/content/renderer/media/stream/media_stream_audio_processor.cc
@@ -665,19 +665,13 @@
   DCHECK(input_format.IsValid());
   input_format_ = input_format;
 
-  // TODO(ajm): For now, we assume fixed parameters for the output when audio
-  // processing is enabled, to match the previous behavior. We should either
-  // use the input parameters (in which case, audio processing will convert
-  // at output) or ideally, have a backchannel from the sink to know what
-  // format it would prefer.
-#if defined(OS_ANDROID)
-  int audio_processing_sample_rate = AudioProcessing::kSampleRate16kHz;
-#else
-  int audio_processing_sample_rate = AudioProcessing::kSampleRate48kHz;
-#endif
-  const int output_sample_rate = audio_processing_ ?
-                                 audio_processing_sample_rate :
-                                 input_format.sample_rate();
+  // TODO(crbug/881275): For now, we assume fixed parameters for the output when
+  // audio processing is enabled, to match the previous behavior. We should
+  // either use the input parameters (in which case, audio processing will
+  // convert at output) or ideally, have a backchannel from the sink to know
+  // what format it would prefer.
+  const int output_sample_rate = audio_processing_ ? kAudioProcessingSampleRate
+                                                   : input_format.sample_rate();
   media::ChannelLayout output_channel_layout = audio_processing_ ?
       media::GuessChannelLayout(kAudioProcessingNumberOfChannels) :
       input_format.channel_layout();
@@ -752,9 +746,10 @@
                render_delay_ms);
 
   int total_delay_ms =  capture_delay_ms + render_delay_ms;
-  if (total_delay_ms > 300) {
+  if (total_delay_ms > 300 && large_delay_log_count_ < 10) {
     LOG(WARNING) << "Large audio delay, capture delay: " << capture_delay_ms
                  << "ms; render delay: " << render_delay_ms << "ms";
+    ++large_delay_log_count_;
   }
 
   webrtc::AudioProcessing* ap = audio_processing_.get();
diff --git a/content/renderer/media/stream/media_stream_audio_processor.h b/content/renderer/media/stream/media_stream_audio_processor.h
index f738f82..edf302f 100644
--- a/content/renderer/media/stream/media_stream_audio_processor.h
+++ b/content/renderer/media/stream/media_stream_audio_processor.h
@@ -213,6 +213,7 @@
   // Counters to avoid excessively logging errors in OnPlayoutData.
   size_t unsupported_buffer_size_log_count_ = 0;
   size_t apm_playout_error_code_log_count_ = 0;
+  size_t large_delay_log_count_ = 0;
 
   // Object for logging UMA stats for echo information when the AEC is enabled.
   // Accessed on the main render thread.
diff --git a/content/renderer/media/stream/media_stream_audio_processor_options.h b/content/renderer/media/stream/media_stream_audio_processor_options.h
index c730fab..f6d6487 100644
--- a/content/renderer/media/stream/media_stream_audio_processor_options.h
+++ b/content/renderer/media/stream/media_stream_audio_processor_options.h
@@ -11,6 +11,7 @@
 #include "base/files/file.h"
 #include "base/macros.h"
 #include "base/threading/thread_checker.h"
+#include "build/build_config.h"
 #include "content/common/content_export.h"
 #include "content/public/common/media_stream_request.h"
 #include "media/audio/audio_processing.h"
@@ -31,6 +32,13 @@
 
 using webrtc::AudioProcessing;
 
+static constexpr int kAudioProcessingSampleRate =
+#if defined(OS_ANDROID)
+    AudioProcessing::kSampleRate16kHz;
+#else
+    AudioProcessing::kSampleRate48kHz;
+#endif
+
 // Simple struct with audio-processing properties.
 struct CONTENT_EXPORT AudioProcessingProperties {
   enum class EchoCancellationType {
diff --git a/content/renderer/media/stream/media_stream_audio_processor_unittest.cc b/content/renderer/media/stream/media_stream_audio_processor_unittest.cc
index 19dff28..b560026 100644
--- a/content/renderer/media/stream/media_stream_audio_processor_unittest.cc
+++ b/content/renderer/media/stream/media_stream_audio_processor_unittest.cc
@@ -44,11 +44,6 @@
 
 namespace {
 
-#if defined(ANDROID)
-const int kAudioProcessingSampleRate = 16000;
-#else
-const int kAudioProcessingSampleRate = 48000;
-#endif
 const int kAudioProcessingNumberOfChannel = 1;
 
 // The number of packers used for testing.
diff --git a/content/renderer/notifications/notification_data_conversions.cc b/content/renderer/notifications/notification_data_conversions.cc
index 65556cd4..72c20d6 100644
--- a/content/renderer/notifications/notification_data_conversions.cc
+++ b/content/renderer/notifications/notification_data_conversions.cc
@@ -20,18 +20,18 @@
 namespace content {
 
 WebNotificationData ToWebNotificationData(
-    const PlatformNotificationData& platform_data) {
+    const blink::PlatformNotificationData& platform_data) {
   WebNotificationData web_data;
   web_data.title = WebString::FromUTF16(platform_data.title);
 
   switch (platform_data.direction) {
-    case PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT:
+    case blink::PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT:
       web_data.direction = WebNotificationData::kDirectionLeftToRight;
       break;
-    case PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT:
+    case blink::PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT:
       web_data.direction = WebNotificationData::kDirectionRightToLeft;
       break;
-    case PlatformNotificationData::DIRECTION_AUTO:
+    case blink::PlatformNotificationData::DIRECTION_AUTO:
       web_data.direction = WebNotificationData::kDirectionAuto;
       break;
   }
@@ -53,10 +53,10 @@
   web_data.actions.Swap(resized);
   for (size_t i = 0; i < platform_data.actions.size(); ++i) {
     switch (platform_data.actions[i].type) {
-      case PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON:
+      case blink::PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON:
         web_data.actions[i].type = blink::WebNotificationAction::kButton;
         break;
-      case PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT:
+      case blink::PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT:
         web_data.actions[i].type = blink::WebNotificationAction::kText;
         break;
       default:
diff --git a/content/renderer/notifications/notification_data_conversions.h b/content/renderer/notifications/notification_data_conversions.h
index d6bf25e..9162657 100644
--- a/content/renderer/notifications/notification_data_conversions.h
+++ b/content/renderer/notifications/notification_data_conversions.h
@@ -6,14 +6,14 @@
 #define CONTENT_RENDERER_NOTIFICATIONS_NOTIFICATION_DATA_CONVERSIONS_H_
 
 #include "content/common/content_export.h"
-#include "content/public/common/platform_notification_data.h"
+#include "third_party/blink/public/common/notifications/platform_notification_data.h"
 #include "third_party/blink/public/platform/modules/notifications/web_notification_data.h"
 
 namespace content {
 
-// Converts PlatformNotificationData to Blink WebNotificationData.
+// Converts blink::PlatformNotificationData to Blink WebNotificationData.
 CONTENT_EXPORT blink::WebNotificationData ToWebNotificationData(
-    const PlatformNotificationData& platform_data);
+    const blink::PlatformNotificationData& platform_data);
 
 }  // namespace content
 
diff --git a/content/renderer/notifications/notification_data_conversions_unittest.cc b/content/renderer/notifications/notification_data_conversions_unittest.cc
index 35fd3f2b..33636ba 100644
--- a/content/renderer/notifications/notification_data_conversions_unittest.cc
+++ b/content/renderer/notifications/notification_data_conversions_unittest.cc
@@ -9,9 +9,9 @@
 
 #include "base/macros.h"
 #include "base/strings/utf_string_conversions.h"
-#include "content/public/common/platform_notification_data.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/public/common/notifications/platform_notification_data.h"
 #include "third_party/blink/public/platform/modules/notifications/web_notification_data.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/platform/web_url.h"
@@ -44,9 +44,10 @@
   std::vector<char> developer_data(
       kNotificationData, kNotificationData + arraysize(kNotificationData));
 
-  PlatformNotificationData platform_data;
+  blink::PlatformNotificationData platform_data;
   platform_data.title = base::ASCIIToUTF16(kNotificationTitle);
-  platform_data.direction = PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT;
+  platform_data.direction =
+      blink::PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT;
   platform_data.lang = kNotificationLang;
   platform_data.body = base::ASCIIToUTF16(kNotificationBody);
   platform_data.tag = kNotificationTag;
@@ -60,13 +61,14 @@
   platform_data.require_interaction = true;
   platform_data.data = developer_data;
   platform_data.actions.resize(2);
-  platform_data.actions[0].type = PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON;
+  platform_data.actions[0].type =
+      blink::PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON;
   platform_data.actions[0].action = kAction1Name;
   platform_data.actions[0].title = base::ASCIIToUTF16(kAction1Title);
   platform_data.actions[0].icon = GURL(kAction1IconUrl);
   platform_data.actions[0].placeholder =
       base::NullableString16(base::ASCIIToUTF16(kAction1Placeholder), false);
-  platform_data.actions[1].type = PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT;
+  platform_data.actions[1].type = blink::PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT;
   platform_data.actions[1].action = kAction2Name;
   platform_data.actions[1].title = base::ASCIIToUTF16(kAction2Title);
   platform_data.actions[1].icon = GURL(kAction2IconUrl);
diff --git a/content/renderer/render_view_impl.cc b/content/renderer/render_view_impl.cc
index c929caa..6e7c7c2 100644
--- a/content/renderer/render_view_impl.cc
+++ b/content/renderer/render_view_impl.cc
@@ -1120,8 +1120,6 @@
   g_view_map.Get().erase(webview_);
   webview_ = nullptr;
   g_routing_id_view_map.Get().erase(GetRoutingID());
-  // TODO(ajwong): Does this message actually get sent?
-  RenderThread::Get()->Send(new ViewHostMsg_Close_ACK(GetRoutingID()));
 }
 
 void RenderViewImpl::ApplyNewSizeForWidget(const gfx::Size& old_size,
@@ -1375,9 +1373,6 @@
     IPC_MESSAGE_HANDLER(PageMsg_UpdateScreenInfo, OnUpdateScreenInfo)
     IPC_MESSAGE_HANDLER(PageMsg_SetPageFrozen, SetPageFrozen)
 
-#if defined(OS_MACOSX)
-    IPC_MESSAGE_HANDLER(ViewMsg_Close, OnClose)
-#endif
     // Adding a new message? Add platform independent ones first, then put the
     // platform specific ones at the end.
 
@@ -2020,17 +2015,6 @@
   Send(new ViewHostMsg_ClosePage_ACK(GetRoutingID()));
 }
 
-#if defined(OS_MACOSX)
-void RenderViewImpl::OnClose() {
-  if (GetWidget()->closing())
-    RenderThread::Get()->Send(new ViewHostMsg_Close_ACK(GetRoutingID()));
-  // This method is protected for OS_MACOSX only, because the message gets sent
-  // to the RenderViewImpl instead of to the RenderWidget.
-  // TODO(danakj): Move this message to RenderWidget?
-  RenderWidget::OnClose();
-}
-#endif
-
 void RenderViewImpl::OnMoveOrResizeStarted() {
   if (webview())
     webview()->HidePopups();
diff --git a/content/renderer/render_view_impl.h b/content/renderer/render_view_impl.h
index 510b766..8b8b606 100644
--- a/content/renderer/render_view_impl.h
+++ b/content/renderer/render_view_impl.h
@@ -448,9 +448,6 @@
   void OnAllowScriptToClose(bool script_can_close);
   void OnCancelDownload(int32_t download_id);
   void OnClosePage();
-#if defined(OS_MACOSX)
-  void OnClose();
-#endif
 
   void OnDeterminePageLanguage();
   void OnDisableScrollbarsForSmallWindows(
diff --git a/content/renderer/render_widget.cc b/content/renderer/render_widget.cc
index a1a3de76..d3e5d79 100644
--- a/content/renderer/render_widget.cc
+++ b/content/renderer/render_widget.cc
@@ -1677,6 +1677,8 @@
   layer_tree_view_.reset();
   if (owner_delegate_)
     owner_delegate_->DidCloseWidget();
+  // Note the ACK is a control message going to the RenderProcessHost.
+  RenderThread::Get()->Send(new ViewHostMsg_Close_ACK(routing_id()));
 }
 
 void RenderWidget::CloseWebWidget() {
diff --git a/content/renderer/render_widget.h b/content/renderer/render_widget.h
index 642e984a..d937458 100644
--- a/content/renderer/render_widget.h
+++ b/content/renderer/render_widget.h
@@ -575,12 +575,6 @@
   // RenderWidget IPC message handler that can be overridden by subclasses.
   virtual void OnSynchronizeVisualProperties(const VisualProperties& params);
 
-#if defined(OS_MACOSX)
-  // On MacOSX this message arrives on RenderViewImpl instead of here, and it
-  // needs to be able to call back to the normal message handler here.
-  void OnClose();
-#endif
-
  private:
   // Friend RefCounted so that the dtor can be non-public. Using this class
   // without ref-counting is an error.
@@ -623,9 +617,7 @@
       const std::vector<const blink::WebInputEvent*>& coalesced_events,
       const ui::LatencyInfo& latency_info,
       InputEventDispatchType dispatch_type);
-#if !defined(OS_MACOSX)
   void OnClose();
-#endif
   void OnCreatingNewAck();
   void OnEnableDeviceEmulation(const blink::WebDeviceEmulationParams& params);
   void OnDisableDeviceEmulation();
diff --git a/content/renderer/renderer_blink_platform_impl.cc b/content/renderer/renderer_blink_platform_impl.cc
index 740296f..5e6b5739 100644
--- a/content/renderer/renderer_blink_platform_impl.cc
+++ b/content/renderer/renderer_blink_platform_impl.cc
@@ -130,7 +130,7 @@
 
 #include "base/synchronization/lock.h"
 #include "content/child/child_process_sandbox_support_impl_linux.h"
-#include "third_party/blink/public/platform/linux/web_fallback_font.h"
+#include "third_party/blink/public/platform/linux/out_of_process_font.h"
 #include "third_party/blink/public/platform/linux/web_sandbox_support.h"
 #include "third_party/icu/source/common/unicode/utf16.h"
 #endif
@@ -222,7 +222,7 @@
   void GetFallbackFontForCharacter(
       blink::WebUChar32 character,
       const char* preferred_locale,
-      blink::WebFallbackFont* fallbackFont) override;
+      blink::OutOfProcessFont* fallbackFont) override;
   void GetWebFontRenderStyleForStrike(const char* family,
                                       int size,
                                       bool is_bold,
@@ -235,7 +235,7 @@
   // unicode code points. It needs this information frequently so we cache it
   // here.
   base::Lock unicode_font_families_mutex_;
-  std::map<int32_t, blink::WebFallbackFont> unicode_font_families_;
+  std::map<int32_t, blink::OutOfProcessFont> unicode_font_families_;
   sk_sp<font_service::FontLoader> font_loader_;
 #endif
 };
@@ -303,7 +303,7 @@
 
 void RendererBlinkPlatformImpl::Shutdown() {
 #if !defined(OS_ANDROID) && !defined(OS_WIN) && !defined(OS_FUCHSIA)
-  // SandboxSupport contains a map of WebFallbackFont objects, which hold
+  // SandboxSupport contains a map of OutOfProcessFont objects, which hold
   // WebStrings and WebVectors, which become invalidated when blink is shut
   // down. Hence, we need to clear that map now, just before blink::shutdown()
   // is called.
@@ -607,9 +607,9 @@
 void RendererBlinkPlatformImpl::SandboxSupport::GetFallbackFontForCharacter(
     blink::WebUChar32 character,
     const char* preferred_locale,
-    blink::WebFallbackFont* fallbackFont) {
+    blink::OutOfProcessFont* fallbackFont) {
   base::AutoLock lock(unicode_font_families_mutex_);
-  const std::map<int32_t, blink::WebFallbackFont>::const_iterator iter =
+  const std::map<int32_t, blink::OutOfProcessFont>::const_iterator iter =
       unicode_font_families_.find(character);
   if (iter != unicode_font_families_.end()) {
     fallbackFont->name = iter->second.name;
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index 22544dc..a46870f5 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -54,7 +54,7 @@
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/public/mojom/request_context_frame_type.mojom.h"
 #include "storage/common/blob_storage/blob_handle.h"
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
 #include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
 #include "third_party/blink/public/common/service_worker/service_worker_utils.h"
 #include "third_party/blink/public/mojom/blob/blob.mojom.h"
@@ -811,6 +811,19 @@
   embedded_worker_client_->WorkerContextDestroyed();
 }
 
+void ServiceWorkerContextClient::FailedToLoadInstalledScript() {
+  DCHECK(worker_task_runner_->RunsTasksInCurrentSequence());
+  TRACE_EVENT_NESTABLE_ASYNC_END1("ServiceWorker", "LOAD_SCRIPT", this,
+                                  "Status", "FailedToLoadInstalledScript");
+  // Cleanly send an OnStopped() message instead of just breaking the
+  // Mojo connection on termination, for consistency with the other
+  // startup failure paths.
+  (*instance_host_)->OnStopped();
+
+  // The caller is responsible for terminating the thread which
+  // eventually destroys |this|.
+}
+
 void ServiceWorkerContextClient::WorkerScriptLoaded() {
   if (!is_starting_installed_worker_)
     (*instance_host_)->OnScriptLoaded();
@@ -1777,7 +1790,7 @@
 
 void ServiceWorkerContextClient::DispatchNotificationClickEvent(
     const std::string& notification_id,
-    const PlatformNotificationData& notification_data,
+    const blink::PlatformNotificationData& notification_data,
     int action_index,
     const base::Optional<base::string16>& reply,
     DispatchNotificationClickEventCallback callback) {
@@ -1803,7 +1816,7 @@
 
 void ServiceWorkerContextClient::DispatchNotificationCloseEvent(
     const std::string& notification_id,
-    const PlatformNotificationData& notification_data,
+    const blink::PlatformNotificationData& notification_data,
     DispatchNotificationCloseEventCallback callback) {
   int request_id = context_->timeout_timer->StartEvent(
       CreateAbortCallback(&context_->notification_close_event_callbacks));
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
index 2a2860c4..1c8de87 100644
--- a/content/renderer/service_worker/service_worker_context_client.h
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -45,8 +45,9 @@
 }
 
 namespace blink {
-class WebDataConsumerHandle;
+struct PlatformNotificationData;
 struct WebServiceWorkerClientQueryOptions;
+class WebDataConsumerHandle;
 class WebServiceWorkerContextProxy;
 class WebServiceWorkerProvider;
 class WebServiceWorkerResponse;
@@ -55,7 +56,6 @@
 
 namespace content {
 
-struct PlatformNotificationData;
 class EmbeddedWorkerInstanceClientImpl;
 class HostChildURLLoaderFactoryBundle;
 class ServiceWorkerNetworkProvider;
@@ -129,6 +129,7 @@
   void ClearCachedMetadata(const blink::WebURL&) override;
   void WorkerReadyForInspection() override;
   void WorkerContextFailedToStart() override;
+  void FailedToLoadInstalledScript() override;
   void WorkerScriptLoaded() override;
   void WorkerContextStarted(
       blink::WebServiceWorkerContextProxy* proxy) override;
@@ -310,13 +311,13 @@
       DispatchFetchEventCallback callback) override;
   void DispatchNotificationClickEvent(
       const std::string& notification_id,
-      const PlatformNotificationData& notification_data,
+      const blink::PlatformNotificationData& notification_data,
       int action_index,
       const base::Optional<base::string16>& reply,
       DispatchNotificationClickEventCallback callback) override;
   void DispatchNotificationCloseEvent(
       const std::string& notification_id,
-      const PlatformNotificationData& notification_data,
+      const blink::PlatformNotificationData& notification_data,
       DispatchNotificationCloseEventCallback callback) override;
   void DispatchPushEvent(const base::Optional<std::string>& payload,
                          DispatchPushEventCallback callback) override;
@@ -345,13 +346,13 @@
   void OnNotificationClickEvent(
       int request_id,
       const std::string& notification_id,
-      const PlatformNotificationData& notification_data,
+      const blink::PlatformNotificationData& notification_data,
       int action_index,
       const base::NullableString16& reply);
   void OnNotificationCloseEvent(
       int request_id,
       const std::string& notification_id,
-      const PlatformNotificationData& notification_data);
+      const blink::PlatformNotificationData& notification_data);
 
   void OnFocusClientResponse(
       int request_id,
diff --git a/content/renderer/service_worker/service_worker_context_client_unittest.cc b/content/renderer/service_worker/service_worker_context_client_unittest.cc
index 273452c..deac479e 100644
--- a/content/renderer/service_worker/service_worker_context_client_unittest.cc
+++ b/content/renderer/service_worker/service_worker_context_client_unittest.cc
@@ -27,7 +27,7 @@
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
 #include "third_party/blink/public/common/service_worker/service_worker_utils.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
 #include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom.h"
diff --git a/content/renderer/service_worker/web_service_worker_provider_impl.cc b/content/renderer/service_worker/web_service_worker_provider_impl.cc
index f4ddf8af..0a66df3 100644
--- a/content/renderer/service_worker/web_service_worker_provider_impl.cc
+++ b/content/renderer/service_worker/web_service_worker_provider_impl.cc
@@ -13,7 +13,7 @@
 #include "content/renderer/service_worker/service_worker_provider_context.h"
 #include "content/renderer/service_worker/web_service_worker_impl.h"
 #include "content/renderer/service_worker/web_service_worker_registration_impl.h"
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_provider_type.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_provider_client.h"
diff --git a/content/renderer/service_worker/web_service_worker_provider_impl.h b/content/renderer/service_worker/web_service_worker_provider_impl.h
index 9c73253..9f60733 100644
--- a/content/renderer/service_worker/web_service_worker_provider_impl.h
+++ b/content/renderer/service_worker/web_service_worker_provider_impl.h
@@ -12,7 +12,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
 #include "content/common/service_worker/service_worker_types.h"
-#include "third_party/blink/public/common/message_port/transferable_message.h"
+#include "third_party/blink/public/common/messaging/transferable_message.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_error_type.mojom.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_registration.mojom.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_provider.h"
diff --git a/content/renderer/shared_worker/embedded_shared_worker_stub.cc b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
index c29ed56..f719c6a2 100644
--- a/content/renderer/shared_worker/embedded_shared_worker_stub.cc
+++ b/content/renderer/shared_worker/embedded_shared_worker_stub.cc
@@ -32,7 +32,7 @@
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
 #include "third_party/blink/public/common/privacy_preferences.h"
 #include "third_party/blink/public/common/service_worker/service_worker_utils.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_object.mojom.h"
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc
index 67e478a..d5eafc0 100644
--- a/content/shell/browser/shell_content_browser_client.cc
+++ b/content/shell/browser/shell_content_browser_client.cc
@@ -386,8 +386,7 @@
   // TODO: implement ShellLoginDialog for other platforms, drop this #if
   return nullptr;
 #else
-  return base::MakeRefCounted<ShellLoginDialog>(
-      auth_info, std::move(auth_required_callback));
+  return ShellLoginDialog::Create(auth_info, std::move(auth_required_callback));
 #endif
 }
 
diff --git a/content/shell/browser/shell_login_dialog.cc b/content/shell/browser/shell_login_dialog.cc
index 2fc0144..136eb09f 100644
--- a/content/shell/browser/shell_login_dialog.cc
+++ b/content/shell/browser/shell_login_dialog.cc
@@ -15,11 +15,23 @@
 
 namespace content {
 
-ShellLoginDialog::ShellLoginDialog(
+// static
+scoped_refptr<ShellLoginDialog> ShellLoginDialog::Create(
     net::AuthChallengeInfo* auth_info,
+    LoginAuthRequiredCallback auth_required_callback) {
+  auto ret = base::WrapRefCounted(
+      new ShellLoginDialog(std::move(auth_required_callback)));
+  ret->Init(auth_info);
+  return ret;
+}
+
+ShellLoginDialog::ShellLoginDialog(
     LoginAuthRequiredCallback auth_required_callback)
     : auth_required_callback_(std::move(auth_required_callback)) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
+}
+
+void ShellLoginDialog::Init(net::AuthChallengeInfo* auth_info) {
   BrowserThread::PostTask(
       BrowserThread::UI, FROM_HERE,
       base::BindOnce(
diff --git a/content/shell/browser/shell_login_dialog.h b/content/shell/browser/shell_login_dialog.h
index 0d52bd5d..a2e760f6 100644
--- a/content/shell/browser/shell_login_dialog.h
+++ b/content/shell/browser/shell_login_dialog.h
@@ -31,11 +31,9 @@
 // ResourceDispatcherHostDelegate::CreateLoginDelegate.
 class ShellLoginDialog : public LoginDelegate {
  public:
-  // Threading: IO thread.
-  ShellLoginDialog(
+  static scoped_refptr<ShellLoginDialog> Create(
       net::AuthChallengeInfo* auth_info,
-      base::OnceCallback<void(const base::Optional<net::AuthCredentials>&)>
-          auth_required_callback);
+      LoginAuthRequiredCallback auth_required_callback);
 
   // LoginDelegate implementation:
   // Threading: IO thread.
@@ -50,9 +48,16 @@
   void UserCancelledAuth();
 
  protected:
+  // Threading: IO thread.
+  ShellLoginDialog(
+      base::OnceCallback<void(const base::Optional<net::AuthCredentials>&)>
+          auth_required_callback);
+
   // Threading: any
   ~ShellLoginDialog() override;
 
+  void Init(net::AuthChallengeInfo* auth_info);
+
  private:
   // All the methods that begin with Platform need to be implemented by the
   // platform specific LoginDialog implementation.
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 7c50c7d..efd9caaf 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1657,7 +1657,6 @@
     "../common/manifest_util_unittest.cc",
     "../common/media/media_devices_unittest.cc",
     "../common/mime_sniffing_throttle_unittest.cc",
-    "../common/notifications/notification_struct_traits_unittest.cc",
     "../common/origin_util_unittest.cc",
     "../common/page_state_serialization_unittest.cc",
     "../common/page_zoom_unittest.cc",
diff --git a/content/test/mock_platform_notification_service.cc b/content/test/mock_platform_notification_service.cc
index b345a74..bf30b76 100644
--- a/content/test/mock_platform_notification_service.cc
+++ b/content/test/mock_platform_notification_service.cc
@@ -11,7 +11,7 @@
 #include "content/public/browser/browser_thread.h"
 #include "content/public/browser/notification_event_dispatcher.h"
 #include "content/public/common/persistent_notification_status.h"
-#include "content/public/common/platform_notification_data.h"
+#include "third_party/blink/public/common/notifications/platform_notification_data.h"
 
 namespace content {
 
@@ -23,8 +23,8 @@
     BrowserContext* browser_context,
     const std::string& notification_id,
     const GURL& origin,
-    const PlatformNotificationData& notification_data,
-    const NotificationResources& notification_resources) {
+    const blink::PlatformNotificationData& notification_data,
+    const blink::NotificationResources& notification_resources) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   ReplaceNotificationIfNeeded(notification_id);
@@ -41,8 +41,8 @@
     const std::string& notification_id,
     const GURL& service_worker_scope,
     const GURL& origin,
-    const PlatformNotificationData& notification_data,
-    const NotificationResources& notification_resources) {
+    const blink::PlatformNotificationData& notification_data,
+    const blink::NotificationResources& notification_resources) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   ReplaceNotificationIfNeeded(notification_id);
diff --git a/content/test/mock_platform_notification_service.h b/content/test/mock_platform_notification_service.h
index 8741d95e..1d38db3e 100644
--- a/content/test/mock_platform_notification_service.h
+++ b/content/test/mock_platform_notification_service.h
@@ -18,10 +18,12 @@
 #include "content/public/browser/platform_notification_service.h"
 #include "url/gurl.h"
 
-namespace content {
-
+namespace blink {
 struct NotificationResources;
 struct PlatformNotificationData;
+}  // namespace blink
+
+namespace content {
 
 // Responsible for tracking active notifications and allowed origins for the
 // Web Notification API when running layout and content tests.
@@ -46,15 +48,15 @@
       BrowserContext* browser_context,
       const std::string& notification_id,
       const GURL& origin,
-      const PlatformNotificationData& notification_data,
-      const NotificationResources& notification_resources) override;
+      const blink::PlatformNotificationData& notification_data,
+      const blink::NotificationResources& notification_resources) override;
   void DisplayPersistentNotification(
       BrowserContext* browser_context,
       const std::string& notification_id,
       const GURL& service_worker_scope,
       const GURL& origin,
-      const PlatformNotificationData& notification_data,
-      const NotificationResources& notification_resources) override;
+      const blink::PlatformNotificationData& notification_data,
+      const blink::NotificationResources& notification_resources) override;
   void CloseNotification(BrowserContext* browser_context,
                          const std::string& notification_id) override;
   void ClosePersistentNotification(BrowserContext* browser_context,
diff --git a/content/utility/utility_blink_platform_with_sandbox_support_impl.cc b/content/utility/utility_blink_platform_with_sandbox_support_impl.cc
index 51eab09..06f79b7 100644
--- a/content/utility/utility_blink_platform_with_sandbox_support_impl.cc
+++ b/content/utility/utility_blink_platform_with_sandbox_support_impl.cc
@@ -15,13 +15,13 @@
 #include "content/child/child_process_sandbox_support_impl_linux.h"
 #include "content/child/child_thread_impl.h"
 #include "services/service_manager/public/cpp/connector.h"
-#include "third_party/blink/public/platform/linux/web_fallback_font.h"
+#include "third_party/blink/public/platform/linux/out_of_process_font.h"
 #include "third_party/blink/public/platform/linux/web_sandbox_support.h"
 #endif
 
 namespace blink {
 class WebSandboxSupport;
-struct WebFallbackFont;
+struct OutOfProcessFont;
 struct WebFontRenderStyle;
 }  // namespace blink
 
@@ -44,7 +44,7 @@
   void GetFallbackFontForCharacter(
       blink::WebUChar32 character,
       const char* preferred_locale,
-      blink::WebFallbackFont* fallbackFont) override;
+      blink::OutOfProcessFont* fallbackFont) override;
   void GetWebFontRenderStyleForStrike(const char* family,
                                       int size,
                                       bool is_bold,
@@ -58,7 +58,7 @@
   // here.
   base::Lock unicode_font_families_mutex_;
   // Maps unicode chars to their fallback fonts.
-  std::map<int32_t, blink::WebFallbackFont> unicode_font_families_;
+  std::map<int32_t, blink::OutOfProcessFont> unicode_font_families_;
   sk_sp<font_service::FontLoader> font_loader_;
 #endif  // defined(OS_MACOSX)
 };
@@ -103,9 +103,9 @@
 void UtilityBlinkPlatformWithSandboxSupportImpl::SandboxSupport::
     GetFallbackFontForCharacter(blink::WebUChar32 character,
                                 const char* preferred_locale,
-                                blink::WebFallbackFont* fallback_font) {
+                                blink::OutOfProcessFont* fallback_font) {
   base::AutoLock lock(unicode_font_families_mutex_);
-  const std::map<int32_t, blink::WebFallbackFont>::const_iterator iter =
+  const std::map<int32_t, blink::OutOfProcessFont>::const_iterator iter =
       unicode_font_families_.find(character);
   if (iter != unicode_font_families_.end()) {
     fallback_font->name = iter->second.name;
diff --git a/extensions/browser/extension_prefs.cc b/extensions/browser/extension_prefs.cc
index e6d8dd4..aa29d85 100644
--- a/extensions/browser/extension_prefs.cc
+++ b/extensions/browser/extension_prefs.cc
@@ -1000,6 +1000,8 @@
     const PermissionSet& permissions) {
   AddToPrefPermissionSet(extension_id, permissions,
                          kPrefRuntimeGrantedPermissions);
+  for (auto& observer : observer_list_)
+    observer.OnExtensionRuntimePermissionsChanged(extension_id);
 }
 
 void ExtensionPrefs::RemoveRuntimeGrantedPermissions(
@@ -1007,6 +1009,8 @@
     const PermissionSet& permissions) {
   RemoveFromPrefPermissionSet(extension_id, permissions,
                               kPrefRuntimeGrantedPermissions);
+  for (auto& observer : observer_list_)
+    observer.OnExtensionRuntimePermissionsChanged(extension_id);
 }
 
 void ExtensionPrefs::SetExtensionRunning(const std::string& extension_id,
diff --git a/extensions/browser/extension_prefs_observer.h b/extensions/browser/extension_prefs_observer.h
index c127979..746a9745a 100644
--- a/extensions/browser/extension_prefs_observer.h
+++ b/extensions/browser/extension_prefs_observer.h
@@ -39,6 +39,14 @@
   // events might not match up.
   virtual void OnExtensionStateChanged(const std::string& extension_id,
                                        bool state) {}
+
+  // Called when the runtime permissions for an extension are changed.
+  // TODO(devlin): This is a bit out of place here, and may be better suited on
+  // a general "extension permissions" observer, if/when we have one. See
+  // discussion at
+  // https://chromium-review.googlesource.com/c/chromium/src/+/1196107/3/chrome/browser/extensions/runtime_permissions_observer.h#26.
+  virtual void OnExtensionRuntimePermissionsChanged(
+      const std::string& extension_id) {}
 };
 
 }  // namespace extensions
diff --git a/extensions/browser/test_event_router_observer.h b/extensions/browser/test_event_router_observer.h
index 7ccd595..4e04bac 100644
--- a/extensions/browser/test_event_router_observer.h
+++ b/extensions/browser/test_event_router_observer.h
@@ -23,8 +23,8 @@
   // Clears all recorded events.
   void ClearEvents();
 
-  const EventMap& events() { return events_; }
-  const EventMap& dispatched_events() { return dispatched_events_; }
+  const EventMap& events() const { return events_; }
+  const EventMap& dispatched_events() const { return dispatched_events_; }
 
  private:
   // EventRouter::TestObserver:
diff --git a/extensions/common/api/_api_features.json b/extensions/common/api/_api_features.json
index 3a7200da..9e94975 100644
--- a/extensions/common/api/_api_features.json
+++ b/extensions/common/api/_api_features.json
@@ -7,7 +7,7 @@
 // well as feature.h, simple_feature.h, and feature_provider.h.
 //
 // Note that specifying "web_page", "blessed_web_page", or "all" as a context
-// type will require manually updating chrome/renderer/resources/dispatcher.cc.
+// type will require manually updating extensions/renderer/extension_bindings_system.cc.
 
 {
   "alarms": {
diff --git a/gin/test/v8_test.cc b/gin/test/v8_test.cc
index 4a68091..e234f2c3 100644
--- a/gin/test/v8_test.cc
+++ b/gin/test/v8_test.cc
@@ -28,9 +28,7 @@
                                  gin::IsolateHolder::kStableV8Extras,
                                  gin::ArrayBufferAllocator::SharedInstance());
 
-  instance_.reset(new gin::IsolateHolder(
-      base::ThreadTaskRunnerHandle::Get(),
-      gin::IsolateHolder::IsolateType::kBlinkMainThread));
+  instance_ = CreateIsolateHolder();
   instance_->isolate()->Enter();
   HandleScope handle_scope(instance_->isolate());
   context_.Reset(instance_->isolate(), Context::New(instance_->isolate()));
@@ -47,4 +45,10 @@
   instance_.reset();
 }
 
+std::unique_ptr<gin::IsolateHolder> V8Test::CreateIsolateHolder() const {
+  return std::make_unique<gin::IsolateHolder>(
+      base::ThreadTaskRunnerHandle::Get(),
+      gin::IsolateHolder::IsolateType::kBlinkMainThread);
+}
+
 }  // namespace gin
diff --git a/gin/test/v8_test.h b/gin/test/v8_test.h
index 383cd134..52c04dd 100644
--- a/gin/test/v8_test.h
+++ b/gin/test/v8_test.h
@@ -28,6 +28,8 @@
   void TearDown() override;
 
  protected:
+  // This is used during SetUp() to initialize instance_.
+  virtual std::unique_ptr<IsolateHolder> CreateIsolateHolder() const;
   base::test::ScopedTaskEnvironment scoped_task_environment_;
   std::unique_ptr<IsolateHolder> instance_;
   v8::Persistent<v8::Context> context_;
diff --git a/gin/v8_isolate_memory_dump_provider.cc b/gin/v8_isolate_memory_dump_provider.cc
index bcf9ffa8..fe14263 100644
--- a/gin/v8_isolate_memory_dump_provider.cc
+++ b/gin/v8_isolate_memory_dump_provider.cc
@@ -90,6 +90,12 @@
 //     - contexts
 //       - detached_context  10
 //       - native_context    20
+//   - workers
+//     - contexts
+//       - detached_context
+//         - isolate_0x1234  10
+//       - native_context
+//         - isolate_0x1234  20
 // ========================================
 void DumpContextStatistics(
     base::trace_event::ProcessMemoryDump* process_memory_dump,
@@ -97,8 +103,7 @@
     std::string dump_name_suffix,
     size_t number_of_detached_contexts,
     size_t number_of_native_contexts) {
-  std::string dump_name_prefix =
-      dump_base_name + "/contexts" + dump_name_suffix;
+  std::string dump_name_prefix = dump_base_name + "/contexts";
   std::string native_context_name =
       dump_name_prefix + "/native_context" + dump_name_suffix;
   auto* native_context_dump =
@@ -106,7 +111,8 @@
   native_context_dump->AddScalar(
       "object_count", base::trace_event::MemoryAllocatorDump::kUnitsObjects,
       number_of_native_contexts);
-  std::string detached_context_name = dump_name_prefix + "/detached_context";
+  std::string detached_context_name =
+      dump_name_prefix + "/detached_context" + dump_name_suffix;
   auto* detached_context_dump =
       process_memory_dump->CreateAllocatorDump(detached_context_name);
   detached_context_dump->AddScalar(
diff --git a/gin/v8_isolate_memory_dump_provider_unittest.cc b/gin/v8_isolate_memory_dump_provider_unittest.cc
index 7a4ad9c..a4241085 100644
--- a/gin/v8_isolate_memory_dump_provider_unittest.cc
+++ b/gin/v8_isolate_memory_dump_provider_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <memory>
 
+#include "base/threading/thread_task_runner_handle.h"
 #include "base/trace_event/process_memory_dump.h"
 #include "base/trace_event/trace_event.h"
 #include "gin/public/isolate_holder.h"
@@ -15,6 +16,15 @@
 
 typedef V8Test V8MemoryDumpProviderTest;
 
+class V8MemoryDumpProviderWorkerTest : public V8MemoryDumpProviderTest {
+ protected:
+  std::unique_ptr<IsolateHolder> CreateIsolateHolder() const override {
+    return std::make_unique<gin::IsolateHolder>(
+        base::ThreadTaskRunnerHandle::Get(),
+        gin::IsolateHolder::IsolateType::kBlinkWorkerThread);
+  }
+};
+
 // Checks if the dump provider runs without crashing and dumps root objects.
 TEST_F(V8MemoryDumpProviderTest, DumpStatistics) {
   // Sets the track objects flag for dumping object statistics. Since this is
@@ -68,10 +78,38 @@
   bool did_dump_native_contexts = false;
   for (const auto& name_dump : allocator_dumps) {
     const std::string& name = name_dump.first;
-    if (name.find("contexts/detached_context") != std::string::npos) {
+    if (name.find("main/contexts/detached_context") != std::string::npos) {
       did_dump_detached_contexts = true;
     }
-    if (name.find("contexts/native_context") != std::string::npos) {
+    if (name.find("main/contexts/native_context") != std::string::npos) {
+      did_dump_native_contexts = true;
+    }
+  }
+
+  ASSERT_TRUE(did_dump_detached_contexts);
+  ASSERT_TRUE(did_dump_native_contexts);
+}
+
+TEST_F(V8MemoryDumpProviderWorkerTest, DumpContextStatistics) {
+  base::trace_event::MemoryDumpArgs dump_args = {
+      base::trace_event::MemoryDumpLevelOfDetail::LIGHT};
+  std::unique_ptr<base::trace_event::ProcessMemoryDump> process_memory_dump(
+      new base::trace_event::ProcessMemoryDump(dump_args));
+  instance_->isolate_memory_dump_provider_for_testing()->OnMemoryDump(
+      dump_args, process_memory_dump.get());
+  const base::trace_event::ProcessMemoryDump::AllocatorDumpsMap&
+      allocator_dumps = process_memory_dump->allocator_dumps();
+
+  bool did_dump_detached_contexts = false;
+  bool did_dump_native_contexts = false;
+  for (const auto& name_dump : allocator_dumps) {
+    const std::string& name = name_dump.first;
+    if (name.find("workers/contexts/detached_context/isolate_0x") !=
+        std::string::npos) {
+      did_dump_detached_contexts = true;
+    }
+    if (name.find("workers/contexts/native_context/isolate_0x") !=
+        std::string::npos) {
       did_dump_native_contexts = true;
     }
   }
diff --git a/google_apis/gaia/gaia_auth_fetcher.cc b/google_apis/gaia/gaia_auth_fetcher.cc
index eaede068..40f73f5 100644
--- a/google_apis/gaia/gaia_auth_fetcher.cc
+++ b/google_apis/gaia/gaia_auth_fetcher.cc
@@ -11,11 +11,15 @@
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
 #include "base/macros.h"
+#include "base/metrics/histogram_functions.h"
+#include "base/metrics/histogram_macros.h"
 #include "base/metrics/user_metrics.h"
 #include "base/metrics/user_metrics_action.h"
+#include "base/process/process_info.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
 #include "base/strings/stringprintf.h"
+#include "base/sys_info.h"
 #include "base/values.h"
 #include "google_apis/gaia/gaia_auth_consumer.h"
 #include "google_apis/gaia/gaia_auth_util.h"
@@ -42,8 +46,8 @@
 
 const size_t kMaxMessageSize = 1024 * 1024;  // 1MB
 
-static bool CookiePartsContains(const std::vector<std::string>& parts,
-                                const char* part) {
+bool CookiePartsContains(const std::vector<std::string>& parts,
+                         const char* part) {
   for (std::vector<std::string>::const_iterator it = parts.begin();
        it != parts.end(); ++it) {
     if (base::LowerCaseEqualsASCII(*it, part))
@@ -819,6 +823,11 @@
 
 void GaiaAuthFetcher::StartListAccounts() {
   DCHECK(!fetch_pending_) << "Tried to fetch two things at once!";
+  list_accounts_system_uptime_ = base::SysInfo::Uptime();
+#if !defined(OS_IOS)
+  list_accounts_process_uptime_ =
+      base::Time::Now() - base::CurrentProcessInfo::CreationTime();
+#endif
 
   net::NetworkTrafficAnnotationTag traffic_annotation =
       net::DefineNetworkTrafficAnnotation("gaia_auth_list_accounts", R"(
@@ -1093,11 +1102,33 @@
 void GaiaAuthFetcher::OnListAccountsFetched(const std::string& data,
                                             net::Error net_error,
                                             int response_code) {
-  if (net_error == net::OK && response_code == net::HTTP_OK) {
-    consumer_->OnListAccountsSuccess(data);
+  // Log error rates and details for ListAccounts, for investigation of
+  // https://crbug.com/876306.
+  base::UmaHistogramSparse("Gaia.AuthFetcher.ListAccounts.NetErrorCodes",
+                           -net_error);
+  if (net_error == net::OK) {
+    UMA_HISTOGRAM_LONG_TIMES(
+        "Gaia.AuthFetcher.ListAccounts.SystemUptime.Success",
+        list_accounts_system_uptime_);
+#if !defined(OS_IOS)
+    UMA_HISTOGRAM_LONG_TIMES(
+        "Gaia.AuthFetcher.ListAccounts.ProcessUptime.Success",
+        list_accounts_process_uptime_);
+#endif
   } else {
-    consumer_->OnListAccountsFailure(GenerateAuthError(data, net_error));
+    UMA_HISTOGRAM_LONG_TIMES("Gaia.AuthFetcher.ListAccounts.SystemUptime.Error",
+                             list_accounts_system_uptime_);
+#if !defined(OS_IOS)
+    UMA_HISTOGRAM_LONG_TIMES(
+        "Gaia.AuthFetcher.ListAccounts.ProcessUptime.Error",
+        list_accounts_process_uptime_);
+#endif
   }
+
+  if (net_error == net::OK && response_code == net::HTTP_OK)
+    consumer_->OnListAccountsSuccess(data);
+  else
+    consumer_->OnListAccountsFailure(GenerateAuthError(data, net_error));
 }
 
 void GaiaAuthFetcher::OnLogOutFetched(const std::string& data,
@@ -1177,6 +1208,7 @@
 void GaiaAuthFetcher::OnOAuthMultiloginFetched(const std::string& data,
                                                net::Error net_error,
                                                int response_code) {
+  GoogleServiceAuthError auth_error = GoogleServiceAuthError::AuthErrorNone();
   if (net_error == net::Error::OK && response_code == net::HTTP_OK) {
     OAuthMultiloginResult result;
     if (!OAuthMultiloginResult::CreateOAuthMultiloginResultFromString(
@@ -1186,8 +1218,12 @@
     } else
       consumer_->OnOAuthMultiloginSuccess(result);
   } else {
-    consumer_->OnOAuthMultiloginFailure(GenerateAuthError(data, net_error));
+    auth_error = GenerateAuthError(data, net_error);
+    consumer_->OnOAuthMultiloginFailure(auth_error);
   }
+  UMA_HISTOGRAM_ENUMERATION("Gaia.AuthFetcher.Multilogin.AuthErrors",
+                            auth_error.state(),
+                            GoogleServiceAuthError::NUM_STATES);
 }
 
 void GaiaAuthFetcher::OnURLLoadComplete(
diff --git a/google_apis/gaia/gaia_auth_fetcher.h b/google_apis/gaia/gaia_auth_fetcher.h
index 8c64de6..f8e7c9f 100644
--- a/google_apis/gaia/gaia_auth_fetcher.h
+++ b/google_apis/gaia/gaia_auth_fetcher.h
@@ -13,6 +13,8 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/time/time.h"
+#include "build/build_config.h"
 #include "google_apis/gaia/gaia_auth_consumer.h"
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "net/base/net_errors.h"
@@ -419,6 +421,13 @@
   bool fetch_pending_ = false;
   bool fetch_token_from_auth_code_ = false;
 
+  // For investigation of https://crbug.com/876306.
+  base::TimeDelta list_accounts_system_uptime_;
+#if !defined(OS_IOS)
+  // There is no easy way to get the process uptime on iOS.
+  base::TimeDelta list_accounts_process_uptime_;
+#endif
+
   friend class GaiaAuthFetcherTest;
   FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, CaptchaParse);
   FRIEND_TEST_ALL_PREFIXES(GaiaAuthFetcherTest, AccountDeletedError);
diff --git a/ios/chrome/app/main_controller.mm b/ios/chrome/app/main_controller.mm
index 3a29181..870afb3 100644
--- a/ios/chrome/app/main_controller.mm
+++ b/ios/chrome/app/main_controller.mm
@@ -32,7 +32,6 @@
 #include "components/metrics/metrics_pref_names.h"
 #include "components/metrics/metrics_service.h"
 #include "components/ntp_snippets/content_suggestions_service.h"
-#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/core/common/passwords_directory_util_ios.h"
 #include "components/payments/core/features.h"
 #include "components/prefs/ios/pref_observer_bridge.h"
@@ -1194,10 +1193,7 @@
   [self sendQueuedFeedback];
   [self scheduleSpotlightResync];
   [self scheduleDeleteDownloadsDirectory];
-  if (base::FeatureList::IsEnabled(
-          password_manager::features::kPasswordExport)) {
-    [self scheduleDeleteTempPasswordsDirectory];
-  }
+  [self scheduleDeleteTempPasswordsDirectory];
   [self scheduleStartupAttemptReset];
   [self startFreeMemoryMonitoring];
   [self scheduleAppDistributionPings];
diff --git a/ios/chrome/browser/about_flags.mm b/ios/chrome/browser/about_flags.mm
index 6174907..c1e4690 100644
--- a/ios/chrome/browser/about_flags.mm
+++ b/ios/chrome/browser/about_flags.mm
@@ -208,9 +208,6 @@
     {"memex-tab-switcher", flag_descriptions::kMemexTabSwitcherName,
      flag_descriptions::kMemexTabSwitcherDescription, flags_ui::kOsIos,
      FEATURE_VALUE_TYPE(kMemexTabSwitcher)},
-    {"PasswordExport", flag_descriptions::kPasswordExportName,
-     flag_descriptions::kPasswordExportDescription, flags_ui::kOsIos,
-     FEATURE_VALUE_TYPE(password_manager::features::kPasswordExport)},
     {"wk-http-system-cookie-store",
      flag_descriptions::kWKHTTPSystemCookieStoreName,
      flag_descriptions::kWKHTTPSystemCookieStoreName, flags_ui::kOsIos,
diff --git a/ios/chrome/browser/autofill/BUILD.gn b/ios/chrome/browser/autofill/BUILD.gn
index a078a38..413549e 100644
--- a/ios/chrome/browser/autofill/BUILD.gn
+++ b/ios/chrome/browser/autofill/BUILD.gn
@@ -52,6 +52,7 @@
     "//base:i18n",
     "//components/autofill/core/browser",
     "//components/autofill/ios/browser",
+    "//components/autofill/ios/form_util",
     "//components/keyed_service/core",
     "//components/keyed_service/ios",
     "//components/prefs",
diff --git a/ios/chrome/browser/autofill/autofill_controller_unittest.mm b/ios/chrome/browser/autofill/autofill_controller_unittest.mm
index 06d8ae2..0c34b28b 100644
--- a/ios/chrome/browser/autofill/autofill_controller_unittest.mm
+++ b/ios/chrome/browser/autofill/autofill_controller_unittest.mm
@@ -62,7 +62,7 @@
 @synthesize suggestions = _suggestions;
 @synthesize suggestionRetrievalComplete = _suggestionRetrievalComplete;
 
-- (void)retrieveSuggestionsForForm:(const web::FormActivityParams&)params
+- (void)retrieveSuggestionsForForm:(const autofill::FormActivityParams&)params
                           webState:(web::WebState*)webState {
   self.suggestionRetrievalComplete = NO;
   [super retrieveSuggestionsForForm:params webState:webState];
diff --git a/ios/chrome/browser/autofill/form_input_accessory_view_provider.h b/ios/chrome/browser/autofill/form_input_accessory_view_provider.h
index d8b2a18..96707d0 100644
--- a/ios/chrome/browser/autofill/form_input_accessory_view_provider.h
+++ b/ios/chrome/browser/autofill/form_input_accessory_view_provider.h
@@ -30,7 +30,7 @@
 // Asynchronously retrieves an accessory view from this provider for the
 // specified form/field and returns it via |accessoryViewUpdateBlock|. View
 // will be nil if no accessories are available from this provider.
-- (void)retrieveAccessoryViewForForm:(const web::FormActivityParams&)params
+- (void)retrieveAccessoryViewForForm:(const autofill::FormActivityParams&)params
                             webState:(web::WebState*)webState
             accessoryViewUpdateBlock:
                 (AccessoryViewReadyCompletion)accessoryViewUpdateBlock;
diff --git a/ios/chrome/browser/autofill/form_suggestion_controller.h b/ios/chrome/browser/autofill/form_suggestion_controller.h
index 9fc9c4b..e11cc728 100644
--- a/ios/chrome/browser/autofill/form_suggestion_controller.h
+++ b/ios/chrome/browser/autofill/form_suggestion_controller.h
@@ -14,9 +14,12 @@
 #import "ios/chrome/browser/autofill/form_suggestion_view_client.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
 
+namespace autofill {
+struct FormActivityParams;
+}
+
 namespace web {
 class WebState;
-struct FormActivityParams;
 }
 
 @protocol CRWWebViewProxy;
@@ -38,7 +41,7 @@
 
 // Finds a FormSuggestionProvider that can supply suggestions for the specified
 // form, requests them, and updates the view accordingly.
-- (void)retrieveSuggestionsForForm:(const web::FormActivityParams&)params
+- (void)retrieveSuggestionsForForm:(const autofill::FormActivityParams&)params
                           webState:(web::WebState*)webState;
 
 // Instructs the controller to detach itself from the WebState.
diff --git a/ios/chrome/browser/autofill/form_suggestion_controller.mm b/ios/chrome/browser/autofill/form_suggestion_controller.mm
index 2d67268d..8575f23 100644
--- a/ios/chrome/browser/autofill/form_suggestion_controller.mm
+++ b/ios/chrome/browser/autofill/form_suggestion_controller.mm
@@ -15,6 +15,7 @@
 #include "components/autofill/core/common/autofill_features.h"
 #import "components/autofill/ios/browser/form_suggestion.h"
 #import "components/autofill/ios/browser/form_suggestion_provider.h"
+#include "components/autofill/ios/form_util/form_activity_params.h"
 #import "ios/chrome/browser/autofill/form_input_accessory_view_controller.h"
 #import "ios/chrome/browser/autofill/form_input_accessory_view_delegate.h"
 #import "ios/chrome/browser/autofill/form_input_accessory_view_provider.h"
@@ -22,7 +23,6 @@
 #import "ios/chrome/browser/passwords/password_generation_utils.h"
 #include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/web/public/url_scheme_util.h"
-#include "ios/web/public/web_state/form_activity_params.h"
 #import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
 #import "ios/web/public/web_state/ui/crw_web_view_proxy.h"
 #import "ios/web/public/web_state/web_state.h"
@@ -186,7 +186,7 @@
   _webViewProxy = webViewProxy;
 }
 
-- (void)retrieveSuggestionsForForm:(const web::FormActivityParams&)params
+- (void)retrieveSuggestionsForForm:(const autofill::FormActivityParams&)params
                           webState:(web::WebState*)webState {
   __weak FormSuggestionController* weakSelf = self;
   NSString* strongFormName = base::SysUTF8ToNSString(params.form_name);
@@ -370,7 +370,7 @@
   _delegate = delegate;
 }
 
-- (void)retrieveAccessoryViewForForm:(const web::FormActivityParams&)params
+- (void)retrieveAccessoryViewForForm:(const autofill::FormActivityParams&)params
                             webState:(web::WebState*)webState
             accessoryViewUpdateBlock:
                 (AccessoryViewReadyCompletion)accessoryViewUpdateBlock {
diff --git a/ios/chrome/browser/autofill/form_suggestion_controller_unittest.mm b/ios/chrome/browser/autofill/form_suggestion_controller_unittest.mm
index d44bc5f..609b148 100644
--- a/ios/chrome/browser/autofill/form_suggestion_controller_unittest.mm
+++ b/ios/chrome/browser/autofill/form_suggestion_controller_unittest.mm
@@ -13,6 +13,7 @@
 #import "components/autofill/ios/browser/form_suggestion.h"
 #import "components/autofill/ios/browser/form_suggestion_provider.h"
 #import "components/autofill/ios/form_util/form_activity_observer_bridge.h"
+#include "components/autofill/ios/form_util/form_activity_params.h"
 #include "components/autofill/ios/form_util/test_form_activity_tab_helper.h"
 #import "ios/chrome/browser/autofill/form_input_accessory_consumer.h"
 #import "ios/chrome/browser/autofill/form_suggestion_view.h"
@@ -20,7 +21,6 @@
 #include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/web/public/navigation_manager.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
-#include "ios/web/public/web_state/form_activity_params.h"
 #import "ios/web/public/web_state/ui/crw_web_view_proxy.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "testing/gtest_mac.h"
@@ -259,7 +259,7 @@
   test_web_state_.SetCurrentURL(GURL("http://foo.com"));
 
   // Trigger form activity, which should set up the suggestions view.
-  web::FormActivityParams params;
+  autofill::FormActivityParams params;
   params.form_name = "form";
   params.field_name = "field";
   params.field_identifier = "field_id";
@@ -278,7 +278,7 @@
 
 // Tests that "blur" events are ignored.
 TEST_F(FormSuggestionControllerTest, FormActivityBlurShouldBeIgnored) {
-  web::FormActivityParams params;
+  autofill::FormActivityParams params;
   params.form_name = "form";
   params.field_name = "field";
   params.field_identifier = "field_id";
@@ -296,7 +296,7 @@
   // Set up the controller without any providers.
   SetUpController(@[]);
   test_web_state_.SetCurrentURL(GURL("http://foo.com"));
-  web::FormActivityParams params;
+  autofill::FormActivityParams params;
   params.form_name = "form";
   params.field_name = "field";
   params.field_identifier = "field_id";
@@ -325,7 +325,7 @@
   SetUpController(@[ provider1, provider2 ]);
   test_web_state_.SetCurrentURL(GURL("http://foo.com"));
 
-  web::FormActivityParams params;
+  autofill::FormActivityParams params;
   params.form_name = "form";
   params.field_name = "field";
   params.field_identifier = "field_id";
@@ -375,7 +375,7 @@
   SetUpController(@[ provider1, provider2 ]);
   test_web_state_.SetCurrentURL(GURL("http://foo.com"));
 
-  web::FormActivityParams params;
+  autofill::FormActivityParams params;
   params.form_name = "form";
   params.field_name = "field";
   params.field_identifier = "field_id";
@@ -415,7 +415,7 @@
       [[TestSuggestionProvider alloc] initWithSuggestions:suggestions];
   SetUpController(@[ provider ]);
   test_web_state_.SetCurrentURL(GURL("http://foo.com"));
-  web::FormActivityParams params;
+  autofill::FormActivityParams params;
   params.form_name = "form";
   params.field_name = "field";
   params.field_identifier = "field_id";
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.cc b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
index a032797..d9a49f0d4 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.cc
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.cc
@@ -209,10 +209,6 @@
     "Use the fullscreen implementation living outside of web. Disable the one "
     "in web.";
 
-const char kPasswordExportName[] = "Password Export";
-const char kPasswordExportDescription[] =
-    "Enables password exporting functionality in password settings.";
-
 const char kPhysicalWeb[] = "Physical Web";
 const char kPhysicalWebDescription[] =
     "When enabled, the omnibox will include suggestions for web pages "
diff --git a/ios/chrome/browser/ios_chrome_flag_descriptions.h b/ios/chrome/browser/ios_chrome_flag_descriptions.h
index b2020a1..3752b1e 100644
--- a/ios/chrome/browser/ios_chrome_flag_descriptions.h
+++ b/ios/chrome/browser/ios_chrome_flag_descriptions.h
@@ -171,11 +171,6 @@
 extern const char kOutOfWebFullscreenName[];
 extern const char kOutOfWebFullscreenDescription[];
 
-// Title and description for the flag to enable the ability to export passwords
-// from the password settings.
-extern const char kPasswordExportName[];
-extern const char kPasswordExportDescription[];
-
 // Title and description for the flag to enable Physical Web in the omnibox.
 extern const char kPhysicalWeb[];
 extern const char kPhysicalWebDescription[];
diff --git a/ios/chrome/browser/ssl/insecure_input_tab_helper.h b/ios/chrome/browser/ssl/insecure_input_tab_helper.h
index 62dd9053..2de6a1f 100644
--- a/ios/chrome/browser/ssl/insecure_input_tab_helper.h
+++ b/ios/chrome/browser/ssl/insecure_input_tab_helper.h
@@ -42,8 +42,9 @@
   explicit InsecureInputTabHelper(web::WebState* web_state);
 
   // FormActivityObserver implementation.
-  void FormActivityRegistered(web::WebState* web_state,
-                              const web::FormActivityParams& params) override;
+  void FormActivityRegistered(
+      web::WebState* web_state,
+      const autofill::FormActivityParams& params) override;
   // WebStateObserver implementation.
   void WebStateDestroyed(web::WebState* web_state) override;
 
diff --git a/ios/chrome/browser/ssl/insecure_input_tab_helper.mm b/ios/chrome/browser/ssl/insecure_input_tab_helper.mm
index d06fd82b..99c6e83 100644
--- a/ios/chrome/browser/ssl/insecure_input_tab_helper.mm
+++ b/ios/chrome/browser/ssl/insecure_input_tab_helper.mm
@@ -9,12 +9,12 @@
 #include <memory>
 
 #include "base/logging.h"
+#include "components/autofill/ios/form_util/form_activity_params.h"
 #include "components/autofill/ios/form_util/form_activity_tab_helper.h"
 #include "components/security_state/ios/ssl_status_input_event_data.h"
 #import "ios/web/public/navigation_item.h"
 #import "ios/web/public/navigation_manager.h"
 #import "ios/web/public/origin_util.h"
-#include "ios/web/public/web_state/form_activity_params.h"
 #import "ios/web/public/web_state/web_state.h"
 #import "ios/web/public/web_state/web_state_user_data.h"
 
@@ -122,7 +122,7 @@
 
 void InsecureInputTabHelper::FormActivityRegistered(
     web::WebState* web_state,
-    const web::FormActivityParams& params) {
+    const autofill::FormActivityParams& params) {
   DCHECK_EQ(web_state_, web_state);
   if (params.type == "input" &&
       !web::IsOriginSecure(web_state->GetLastCommittedURL())) {
diff --git a/ios/chrome/browser/ui/autofill/form_input_accessory_mediator.mm b/ios/chrome/browser/ui/autofill/form_input_accessory_mediator.mm
index 6569a68..d8d3b6e8 100644
--- a/ios/chrome/browser/ui/autofill/form_input_accessory_mediator.mm
+++ b/ios/chrome/browser/ui/autofill/form_input_accessory_mediator.mm
@@ -9,6 +9,7 @@
 #include "base/mac/scoped_block.h"
 #import "components/autofill/ios/browser/js_suggestion_manager.h"
 #import "components/autofill/ios/form_util/form_activity_observer_bridge.h"
+#include "components/autofill/ios/form_util/form_activity_params.h"
 #import "ios/chrome/browser/autofill/form_input_accessory_consumer.h"
 #import "ios/chrome/browser/autofill/form_input_accessory_view_handler.h"
 #import "ios/chrome/browser/autofill/form_input_accessory_view_provider.h"
@@ -17,7 +18,6 @@
 #include "ios/chrome/browser/ui/ui_util.h"
 #import "ios/chrome/browser/web_state_list/web_state_list.h"
 #import "ios/web/public/url_scheme_util.h"
-#include "ios/web/public/web_state/form_activity_params.h"
 #import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
 #include "ios/web/public/web_state/web_state.h"
 
@@ -143,7 +143,7 @@
 #pragma mark - FormActivityObserver
 
 - (void)webState:(web::WebState*)webState
-    didRegisterFormActivity:(const web::FormActivityParams&)params {
+    didRegisterFormActivity:(const autofill::FormActivityParams&)params {
   DCHECK_EQ(_webState, webState);
   web::URLVerificationTrustLevel trustLevel;
   const GURL pageURL(webState->GetCurrentURL(&trustLevel));
@@ -238,7 +238,7 @@
 
 // Asynchronously queries the providers for an accessory view. Sends it to
 // the consumer if found.
-- (void)retrieveAccessoryViewForForm:(const web::FormActivityParams&)params
+- (void)retrieveAccessoryViewForForm:(const autofill::FormActivityParams&)params
                             webState:(web::WebState*)webState {
   DCHECK_EQ(webState, self.webState);
   // Build a block for each provider that will invoke its completion with YES
@@ -267,7 +267,7 @@
 // params.
 - (passwords::PipelineBlock)
 queryViewBlockForProvider:(id<FormInputAccessoryViewProvider>)provider
-                   params:(web::FormActivityParams)params {
+                   params:(autofill::FormActivityParams)params {
   __weak __typeof(self) weakSelf = self;
   return ^(void (^completion)(BOOL success)) {
     FormInputAccessoryMediator* strongSelf = weakSelf;
diff --git a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
index cf7d7d2..6e0ae4d5 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmark_home_view_controller.mm
@@ -473,7 +473,6 @@
   // Configure the table view.
   self.sharedState.tableView.accessibilityIdentifier = @"bookmarksTableView";
   self.sharedState.tableView.estimatedRowHeight = kEstimatedRowHeight;
-  self.sharedState.tableView.rowHeight = UITableViewAutomaticDimension;
   self.tableView.sectionHeaderHeight = 0;
   // Setting a sectionFooterHeight of 0 will be the same as not having a
   // footerView, which shows a cell separator for the last cell. Removing this
@@ -1886,6 +1885,16 @@
 
 #pragma mark - UITableViewDelegate
 
+- (CGFloat)tableView:(UITableView*)tableView
+    heightForRowAtIndexPath:(NSIndexPath*)indexPath {
+  NSInteger sectionIdentifier = [self.sharedState.tableViewModel
+      sectionIdentifierForSection:indexPath.section];
+  if (sectionIdentifier == BookmarkHomeSectionIdentifierBookmarks) {
+    return kEstimatedRowHeight;
+  }
+  return UITableViewAutomaticDimension;
+}
+
 - (void)tableView:(UITableView*)tableView
     didSelectRowAtIndexPath:(NSIndexPath*)indexPath {
   NSInteger sectionIdentifier = [self.sharedState.tableViewModel
diff --git a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
index 94a1f31..e8a2773 100644
--- a/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
+++ b/ios/chrome/browser/ui/bookmarks/bookmarks_egtest.mm
@@ -885,8 +885,7 @@
 
   // Ensure the Bottom 1 of Folder 1 is visible.  That means both folder and
   // scroll position are restored successfully.
-  [[EarlGrey
-      selectElementWithMatcher:grey_accessibilityLabel(@"Bottom 1, 127.0.0.1")]
+  [[EarlGrey selectElementWithMatcher:grey_accessibilityID(@"Bottom 1")]
       assertWithMatcher:grey_sufficientlyVisible()];
 }
 
@@ -1089,8 +1088,6 @@
                          base::SysNSStringToUTF16(@"Top URL"), dummyURL);
 
   // Add URLs to Folder 1.
-  bookmark_model->AddURL(folder1, 0, base::SysNSStringToUTF16(dummyTitle),
-                         dummyURL);
   bookmark_model->AddURL(folder1, 0, base::SysNSStringToUTF16(@"Bottom 1"),
                          dummyURL);
   for (int i = 0; i < 20; i++) {
@@ -1606,7 +1603,7 @@
   // verify the editable textfield is gone.
   [[EarlGrey
       selectElementWithMatcher:grey_accessibilityID(@"bookmark_editing_text")]
-      assertWithMatcher:grey_notVisible()];
+      assertWithMatcher:grey_nil()];
 }
 
 + (void)tapOnContextMenuButton:(int)menuButtonId
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm
index d5aae12..45fa7bd 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_collection_updater.mm
@@ -365,7 +365,9 @@
                                   completion:nil];
                    }];
 
-  // Make sure we get the right index for the section.
+  // Make sure the section is still in the model and that the index is correct.
+  if (![model hasSectionForSectionIdentifier:sectionIdentifier])
+    return;
   section = [model sectionForSectionIdentifier:sectionIdentifier];
 
   [self.collectionViewController.collectionView
diff --git a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
index 29df5ca..f45a384 100644
--- a/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
+++ b/ios/chrome/browser/ui/content_suggestions/content_suggestions_header_view_controller.mm
@@ -517,7 +517,16 @@
 #pragma mark - LogoAnimationControllerOwnerOwner
 
 - (id<LogoAnimationControllerOwner>)logoAnimationControllerOwner {
-  return [self.logoVendor logoAnimationControllerOwner];
+  // Only return the logo vendor's animation controller owner if the logo view
+  // is fully visible.  This prevents the logo from being used in transition
+  // animations if the logo has been scrolled off screen.
+  UIView* logoView = self.logoVendor.view;
+  UIView* parentView = self.parentViewController.view;
+  CGRect logoFrame = [parentView convertRect:logoView.bounds fromView:logoView];
+  BOOL isLogoFullyVisible = CGRectEqualToRect(
+      CGRectIntersection(logoFrame, parentView.bounds), logoFrame);
+  return isLogoFullyVisible ? [self.logoVendor logoAnimationControllerOwner]
+                            : nil;
 }
 
 #pragma mark - NTPHomeConsumer
diff --git a/ios/chrome/browser/ui/download/download_manager_coordinator.mm b/ios/chrome/browser/ui/download/download_manager_coordinator.mm
index 9cda620..2c975782 100644
--- a/ios/chrome/browser/ui/download/download_manager_coordinator.mm
+++ b/ios/chrome/browser/ui/download/download_manager_coordinator.mm
@@ -271,7 +271,9 @@
                                     : DownloadedFileAction::OpenedInOtherApp;
   UMA_HISTOGRAM_ENUMERATION("Download.IOSDownloadedFileAction", action,
                             DownloadedFileAction::Count);
-  _unopenedDownloads.Remove(_downloadTask);
+  if (_downloadTask) {  // _downloadTask can be null if coordinator was stopped.
+    _unopenedDownloads.Remove(_downloadTask);
+  }
 }
 
 #pragma mark - ContainedPresenterDelegate
diff --git a/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm b/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
index cdefd3c73..e1701ea 100644
--- a/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
+++ b/ios/chrome/browser/ui/reading_list/reading_list_table_view_controller.mm
@@ -80,6 +80,8 @@
     BOOL editingWithToolbarButtons;
 // Whether the table view is being edited by the swipe-to-delete button.
 @property(nonatomic, readonly, getter=isEditingWithSwipe) BOOL editingWithSwipe;
+// Whether to remove empty sections after editing is reset to NO.
+@property(nonatomic, assign) BOOL needsSectionCleanupAfterEditing;
 
 @end
 
@@ -94,6 +96,7 @@
 @synthesize selectedReadItemCount = _selectedReadItemCount;
 @synthesize markConfirmationSheet = _markConfirmationSheet;
 @synthesize editingWithToolbarButtons = _editingWithToolbarButtons;
+@synthesize needsSectionCleanupAfterEditing = _needsSectionCleanupAfterEditing;
 
 - (instancetype)init {
   self = [super initWithTableViewStyle:UITableViewStylePlain
@@ -130,8 +133,13 @@
   self.selectedUnreadItemCount = 0;
   self.selectedReadItemCount = 0;
   [self updateToolbarItems];
-  if (!editing)
+  if (!editing) {
     self.editingWithToolbarButtons = NO;
+    if (self.needsSectionCleanupAfterEditing) {
+      [self removeEmptySections];
+      self.needsSectionCleanupAfterEditing = NO;
+    }
+  }
 }
 
 - (void)setSelectedUnreadItemCount:(NSUInteger)selectedUnreadItemCount {
@@ -223,7 +231,15 @@
      forRowAtIndexPath:(NSIndexPath*)indexPath {
   DCHECK_EQ(editingStyle, UITableViewCellEditingStyleDelete);
   base::RecordAction(base::UserMetricsAction("MobileReadingListDeleteEntry"));
-  [self deleteItemsAtIndexPaths:@[ indexPath ]];
+  // The UIKit animation for the swipe-to-delete gesture throws an exception if
+  // the section of the deleted item is removed before the animation is
+  // finished.  To prevent this from happening, record that cleanup is needed
+  // and remove the section when self.tableView.editing is reset to NO when the
+  // animation finishes.
+  self.needsSectionCleanupAfterEditing = YES;
+  [self deleteItemsAtIndexPaths:@[ indexPath ]
+                     endEditing:NO
+            removeEmptySections:NO];
 }
 
 #pragma mark - UITableViewDelegate
@@ -728,14 +744,26 @@
   return [self itemsForSection:sectionID].count > 0;
 }
 
-// Deletes the items at |indexPaths|.
+// Deletes the items at |indexPaths|, exiting editing and removing empty
+// sections upon completion.
 - (void)deleteItemsAtIndexPaths:(NSArray<NSIndexPath*>*)indexPaths {
+  [self deleteItemsAtIndexPaths:indexPaths
+                     endEditing:YES
+            removeEmptySections:YES];
+}
+
+// Deletes the items at |indexPaths|.  Exits editing mode if |endEditing| is
+// YES.  Removes empty sections upon completion if |removeEmptySections| is YES.
+- (void)deleteItemsAtIndexPaths:(NSArray<NSIndexPath*>*)indexPaths
+                     endEditing:(BOOL)endEditing
+            removeEmptySections:(BOOL)removeEmptySections {
   // Delete the items in the data source and exit editing mode.
   ReadingListListItemUpdater updater = ^(id<ReadingListListItem> item) {
     [self.dataSource removeEntryFromItem:item];
   };
   [self updateItemsAtIndexPaths:indexPaths withItemUpdater:updater];
-  [self exitEditingModeAnimated:YES];
+  if (endEditing)
+    [self exitEditingModeAnimated:YES];
 
   // Update the model and table view for the deleted items.
   UITableView* tableView = self.tableView;
@@ -749,9 +777,13 @@
     [tableView deleteRowsAtIndexPaths:indexPaths
                      withRowAnimation:UITableViewRowAnimationAutomatic];
   };
-  void (^completion)(BOOL) = ^(BOOL) {
-    [self batchEditDidFinish];
-  };
+
+  void (^completion)(BOOL) = nil;
+  if (removeEmptySections) {
+    completion = ^(BOOL) {
+      [self batchEditDidFinish];
+    };
+  }
   [self performBatchTableViewUpdates:updates completion:completion];
 }
 
diff --git a/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm b/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm
index 2fc12b9..2c3917c1 100644
--- a/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm
+++ b/ios/chrome/browser/ui/settings/passwords_settings_egtest.mm
@@ -17,7 +17,6 @@
 #include "components/keyed_service/core/service_access_type.h"
 #include "components/password_manager/core/browser/password_store.h"
 #include "components/password_manager/core/browser/password_store_consumer.h"
-#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/prefs/pref_service.h"
 #include "components/strings/grit/components_strings.h"
@@ -1551,10 +1550,6 @@
 
 // Test export flow
 - (void)testExportFlow {
-  if (!base::FeatureList::IsEnabled(
-          password_manager::features::kPasswordExport)) {
-    return;
-  }
   // Saving a form is needed for exporting passwords.
   SaveExamplePasswordForm();
 
diff --git a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm
index 24e58bdd..b9445b6 100644
--- a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm
+++ b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller.mm
@@ -21,7 +21,6 @@
 #include "components/password_manager/core/browser/password_manager_metrics_util.h"
 #include "components/password_manager/core/browser/password_store.h"
 #include "components/password_manager/core/browser/password_ui_utils.h"
-#include "components/password_manager/core/common/password_manager_features.h"
 #include "components/password_manager/core/common/password_manager_pref_names.h"
 #include "components/prefs/pref_member.h"
 #include "components/prefs/pref_service.h"
@@ -224,12 +223,9 @@
     browserState_ = browserState;
     reauthenticationModule_ = [[ReauthenticationModule alloc]
         initWithSuccessfulReauthTimeAccessor:self];
-    if (base::FeatureList::IsEnabled(
-            password_manager::features::kPasswordExport)) {
-      passwordExporter_ = [[PasswordExporter alloc]
-          initWithReauthenticationModule:reauthenticationModule_
-                                delegate:self];
-    }
+    passwordExporter_ = [[PasswordExporter alloc]
+        initWithReauthenticationModule:reauthenticationModule_
+                              delegate:self];
     self.title = l10n_util::GetNSString(IDS_IOS_PASSWORDS);
     self.collectionViewAccessibilityIdentifier =
         @"SavePasswordsCollectionViewController";
@@ -307,14 +303,11 @@
         forSectionWithIdentifier:SectionIdentifierBlacklist];
   }
 
-  if (base::FeatureList::IsEnabled(
-          password_manager::features::kPasswordExport)) {
-    // Export passwords button.
-    [model addSectionWithIdentifier:SectionIdentifierExportPasswordsButton];
-    exportPasswordsItem_ = [self exportPasswordsItem];
-    [model addItem:exportPasswordsItem_
-        toSectionWithIdentifier:SectionIdentifierExportPasswordsButton];
-  }
+  // Export passwords button.
+  [model addSectionWithIdentifier:SectionIdentifierExportPasswordsButton];
+  exportPasswordsItem_ = [self exportPasswordsItem];
+  [model addItem:exportPasswordsItem_
+      toSectionWithIdentifier:SectionIdentifierExportPasswordsButton];
 
   [self filterItems:self.searchTerm];
 }
@@ -606,8 +599,7 @@
 }
 
 - (void)updateExportPasswordsButton {
-  if (!exportPasswordsItem_ || !base::FeatureList::IsEnabled(
-                                   password_manager::features::kPasswordExport))
+  if (!exportPasswordsItem_)
     return;
   if (!savedForms_.empty() &&
       self.passwordExporter.exportState == ExportState::IDLE) {
@@ -733,8 +725,6 @@
     case ItemTypeExportPasswordsButton:
       DCHECK_EQ(SectionIdentifierExportPasswordsButton,
                 [model sectionIdentifierForSection:indexPath.section]);
-      DCHECK(base::FeatureList::IsEnabled(
-          password_manager::features::kPasswordExport));
       if (exportReady_) {
         [self startPasswordsExportFlow];
       }
@@ -759,10 +749,7 @@
   [super collectionViewWillBeginEditing:collectionView];
 
   [self setSavePasswordsSwitchItemEnabled:NO];
-  if (base::FeatureList::IsEnabled(
-          password_manager::features::kPasswordExport)) {
-    [self setExportPasswordsButtonEnabled:NO];
-  }
+  [self setExportPasswordsButtonEnabled:NO];
   [self setSearchPasswordsItemEnabled:NO];
 }
 
@@ -770,11 +757,8 @@
   [super collectionViewWillEndEditing:collectionView];
 
   [self setSavePasswordsSwitchItemEnabled:YES];
-  if (base::FeatureList::IsEnabled(
-          password_manager::features::kPasswordExport)) {
-    if (exportReady_) {
-      [self setExportPasswordsButtonEnabled:YES];
-    }
+  if (exportReady_) {
+    [self setExportPasswordsButtonEnabled:YES];
   }
   [self setSearchPasswordsItemEnabled:YES];
 }
diff --git a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller_unittest.mm b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller_unittest.mm
index 53fd50d9e6..04537be08 100644
--- a/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller_unittest.mm
+++ b/ios/chrome/browser/ui/settings/save_passwords_collection_view_controller_unittest.mm
@@ -10,7 +10,6 @@
 #include "base/compiler_specific.h"
 #include "base/strings/utf_string_conversions.h"
 #import "base/test/ios/wait_util.h"
-#include "base/test/scoped_feature_list.h"
 #include "components/autofill/core/common/password_form.h"
 #include "components/keyed_service/core/service_access_type.h"
 #include "components/password_manager/core/browser/mock_password_store.h"
@@ -51,21 +50,11 @@
 } ExportPasswordsFeatureStatus;
 
 class SavePasswordsCollectionViewControllerTest
-    : public CollectionViewControllerTest,
-      public ::testing::WithParamInterface<ExportPasswordsFeatureStatus> {
+    : public CollectionViewControllerTest {
  protected:
   SavePasswordsCollectionViewControllerTest() = default;
 
   void SetUp() override {
-    // TODO(crbug.com/792840): Remove parametrized tests once the feature is
-    // enabled.
-    if (GetParam().export_enabled) {
-      scoped_feature_list_.InitAndEnableFeature(
-          password_manager::features::kPasswordExport);
-    } else {
-      scoped_feature_list_.InitAndDisableFeature(
-          password_manager::features::kPasswordExport);
-    }
     TestChromeBrowserState::Builder test_cbs_builder;
     chrome_browser_state_ = test_cbs_builder.Build();
     CollectionViewControllerTest::SetUp();
@@ -169,45 +158,39 @@
 
   web::TestWebThreadBundle thread_bundle_;
   std::unique_ptr<TestChromeBrowserState> chrome_browser_state_;
-  base::test::ScopedFeatureList scoped_feature_list_;
 };
 
 // Tests default case has no saved sites and no blacklisted sites.
-TEST_P(SavePasswordsCollectionViewControllerTest, TestInitialization) {
+TEST_F(SavePasswordsCollectionViewControllerTest, TestInitialization) {
   CheckController();
-  EXPECT_EQ(GetParam().section_offset + 2, NumberOfSections());
+  EXPECT_EQ(3, NumberOfSections());
 }
 
 // Tests adding one item in saved password section.
-TEST_P(SavePasswordsCollectionViewControllerTest, AddSavedPasswords) {
+TEST_F(SavePasswordsCollectionViewControllerTest, AddSavedPasswords) {
   AddSavedForm1();
 
-  int section_offset = GetParam().section_offset;
-  EXPECT_EQ(section_offset + 4, NumberOfSections());
+  EXPECT_EQ(5, NumberOfSections());
   EXPECT_EQ(1, NumberOfItemsInSection(3));
 }
 
 // Tests adding one item in blacklisted password section.
-TEST_P(SavePasswordsCollectionViewControllerTest, AddBlacklistedPasswords) {
+TEST_F(SavePasswordsCollectionViewControllerTest, AddBlacklistedPasswords) {
   AddBlacklistedForm1();
 
-  int section_offset = GetParam().section_offset;
-
-  EXPECT_EQ(section_offset + 4, NumberOfSections());
+  EXPECT_EQ(5, NumberOfSections());
   EXPECT_EQ(1, NumberOfItemsInSection(3));
 }
 
 // Tests adding one item in saved password section, and two items in blacklisted
 // password section.
-TEST_P(SavePasswordsCollectionViewControllerTest, AddSavedAndBlacklisted) {
+TEST_F(SavePasswordsCollectionViewControllerTest, AddSavedAndBlacklisted) {
   AddSavedForm1();
   AddBlacklistedForm1();
   AddBlacklistedForm2();
 
-  int section_offset = GetParam().section_offset;
-
   // There should be two sections added.
-  EXPECT_EQ(section_offset + 5, NumberOfSections());
+  EXPECT_EQ(6, NumberOfSections());
 
   // There should be 1 row in saved password section.
   EXPECT_EQ(1, NumberOfItemsInSection(3));
@@ -216,7 +199,7 @@
 }
 
 // Tests the order in which the saved passwords are displayed.
-TEST_P(SavePasswordsCollectionViewControllerTest, TestSavedPasswordsOrder) {
+TEST_F(SavePasswordsCollectionViewControllerTest, TestSavedPasswordsOrder) {
   AddSavedForm2();
 
   CheckTextCellTitleAndSubtitle(@"example2.com", @"test@egmail.com", 3, 0);
@@ -227,7 +210,7 @@
 }
 
 // Tests the order in which the blacklisted passwords are displayed.
-TEST_P(SavePasswordsCollectionViewControllerTest,
+TEST_F(SavePasswordsCollectionViewControllerTest,
        TestBlacklistedPasswordsOrder) {
   AddBlacklistedForm2();
   CheckTextCellTitle(@"secret2.com", 3, 0);
@@ -239,30 +222,26 @@
 
 // Tests displaying passwords in the saved passwords section when there are
 // duplicates in the password store.
-TEST_P(SavePasswordsCollectionViewControllerTest, AddSavedDuplicates) {
+TEST_F(SavePasswordsCollectionViewControllerTest, AddSavedDuplicates) {
   AddSavedForm1();
   AddSavedForm1();
 
-  int section_offset = GetParam().section_offset;
-
-  EXPECT_EQ(section_offset + 4, NumberOfSections());
+  EXPECT_EQ(5, NumberOfSections());
   EXPECT_EQ(1, NumberOfItemsInSection(3));
 }
 
 // Tests displaying passwords in the blacklisted passwords section when there
 // are duplicates in the password store.
-TEST_P(SavePasswordsCollectionViewControllerTest, AddBlacklistedDuplicates) {
+TEST_F(SavePasswordsCollectionViewControllerTest, AddBlacklistedDuplicates) {
   AddBlacklistedForm1();
   AddBlacklistedForm1();
 
-  int section_offset = GetParam().section_offset;
-
-  EXPECT_EQ(section_offset + 4, NumberOfSections());
+  EXPECT_EQ(5, NumberOfSections());
   EXPECT_EQ(1, NumberOfItemsInSection(3));
 }
 
 // Tests deleting items from saved passwords and blacklisted passwords sections.
-TEST_P(SavePasswordsCollectionViewControllerTest, DeleteItems) {
+TEST_F(SavePasswordsCollectionViewControllerTest, DeleteItems) {
   AddSavedForm1();
   AddBlacklistedForm1();
   AddBlacklistedForm2();
@@ -278,11 +257,9 @@
         }));
   };
 
-  int section_offset = GetParam().section_offset;
-
   // Delete item in save passwords section.
   deleteItemWithWait(3, 0);
-  EXPECT_EQ(section_offset + 4, NumberOfSections());
+  EXPECT_EQ(5, NumberOfSections());
   // Section 3 should now be the blacklisted passwords section, and should still
   // have both its items.
   EXPECT_EQ(2, NumberOfItemsInSection(3));
@@ -292,12 +269,12 @@
   EXPECT_EQ(1, NumberOfItemsInSection(3));
   deleteItemWithWait(3, 0);
   // There should be no password sections remaining and no search bar.
-  EXPECT_EQ(section_offset + 2, NumberOfSections());
+  EXPECT_EQ(3, NumberOfSections());
 }
 
 // Tests deleting items from saved passwords and blacklisted passwords sections
 // when there are duplicates in the store.
-TEST_P(SavePasswordsCollectionViewControllerTest, DeleteItemsWithDuplicates) {
+TEST_F(SavePasswordsCollectionViewControllerTest, DeleteItemsWithDuplicates) {
   AddSavedForm1();
   AddSavedForm1();
   AddBlacklistedForm1();
@@ -315,11 +292,9 @@
         }));
   };
 
-  int section_offset = GetParam().section_offset;
-
   // Delete item in save passwords section.
   deleteItemWithWait(3, 0);
-  EXPECT_EQ(section_offset + 4, NumberOfSections());
+  EXPECT_EQ(5, NumberOfSections());
   // Section 3 should now be the blacklisted passwords section, and should still
   // have both its items.
   EXPECT_EQ(2, NumberOfItemsInSection(3));
@@ -329,14 +304,11 @@
   EXPECT_EQ(1, NumberOfItemsInSection(3));
   deleteItemWithWait(3, 0);
   // There should be no password sections remaining and no search bar.
-  EXPECT_EQ(section_offset + 2, NumberOfSections());
+  EXPECT_EQ(3, NumberOfSections());
 }
 
-TEST_P(SavePasswordsCollectionViewControllerTest,
+TEST_F(SavePasswordsCollectionViewControllerTest,
        TestExportButtonDisabledNoSavedPasswords) {
-  if (!GetParam().export_enabled)
-    return;
-
   SavePasswordsCollectionViewController* save_password_controller =
       static_cast<SavePasswordsCollectionViewController*>(controller());
   [save_password_controller updateExportPasswordsButton];
@@ -358,11 +330,8 @@
               UIAccessibilityTraitNotEnabled);
 }
 
-TEST_P(SavePasswordsCollectionViewControllerTest,
+TEST_F(SavePasswordsCollectionViewControllerTest,
        TestExportButtonEnabledWithSavedPasswords) {
-  if (!GetParam().export_enabled)
-    return;
-
   SavePasswordsCollectionViewController* save_password_controller =
       static_cast<SavePasswordsCollectionViewController*>(controller());
   AddSavedForm1();
@@ -377,11 +346,8 @@
 }
 
 // Tests that the "Export Passwords..." button is greyed out in edit mode.
-TEST_P(SavePasswordsCollectionViewControllerTest,
+TEST_F(SavePasswordsCollectionViewControllerTest,
        TestExportButtonDisabledEditMode) {
-  if (!GetParam().export_enabled)
-    return;
-
   SavePasswordsCollectionViewController* save_password_controller =
       static_cast<SavePasswordsCollectionViewController*>(controller());
   AddSavedForm1();
@@ -400,11 +366,8 @@
 
 // Tests that the "Export Passwords..." button is enabled after exiting
 // edit mode.
-TEST_P(SavePasswordsCollectionViewControllerTest,
+TEST_F(SavePasswordsCollectionViewControllerTest,
        TestExportButtonEnabledWhenEdittingFinished) {
-  if (!GetParam().export_enabled)
-    return;
-
   SavePasswordsCollectionViewController* save_password_controller =
       static_cast<SavePasswordsCollectionViewController*>(controller());
   AddSavedForm1();
@@ -423,7 +386,7 @@
                UIAccessibilityTraitNotEnabled);
 }
 
-TEST_P(SavePasswordsCollectionViewControllerTest, PropagateDeletionToStore) {
+TEST_F(SavePasswordsCollectionViewControllerTest, PropagateDeletionToStore) {
   SavePasswordsCollectionViewController* save_password_controller =
       static_cast<SavePasswordsCollectionViewController*>(controller());
   autofill::PasswordForm form;
@@ -445,14 +408,13 @@
 }
 
 // Tests filtering of items.
-TEST_P(SavePasswordsCollectionViewControllerTest, FilterItems) {
+TEST_F(SavePasswordsCollectionViewControllerTest, FilterItems) {
   AddSavedForm1();
   AddSavedForm2();
   AddBlacklistedForm1();
   AddBlacklistedForm2();
 
-  int section_offset = GetParam().section_offset;
-  EXPECT_EQ(section_offset + 5, NumberOfSections());
+  EXPECT_EQ(6, NumberOfSections());
 
   SavePasswordsCollectionViewController* save_password_controller =
       static_cast<SavePasswordsCollectionViewController*>(controller());
@@ -488,14 +450,4 @@
   EXPECT_EQ(2, NumberOfItemsInSection(4));
 }
 
-const std::vector<ExportPasswordsFeatureStatus> kExportFeatureStatusCases{
-    // Passwords export disabled
-    {FALSE, 0},
-    // Passwords export enabled
-    {TRUE, 1}};
-
-INSTANTIATE_TEST_CASE_P(ExportDisabledAndEnabled,
-                        SavePasswordsCollectionViewControllerTest,
-                        ::testing::ValuesIn(kExportFeatureStatusCases));
-
 }  // namespace
diff --git a/ios/third_party/material_components_ios/BUILD.gn b/ios/third_party/material_components_ios/BUILD.gn
index b60c6680..67f6ded 100644
--- a/ios/third_party/material_components_ios/BUILD.gn
+++ b/ios/third_party/material_components_ios/BUILD.gn
@@ -67,12 +67,19 @@
     "src/components/AnimationTiming/src/MaterialAnimationTiming.h",
     "src/components/AnimationTiming/src/UIView+MDCTimingFunction.h",
     "src/components/AnimationTiming/src/UIView+MDCTimingFunction.m",
+    "src/components/AppBar/src/ColorThemer/MDCAppBarColorThemer.h",
+    "src/components/AppBar/src/ColorThemer/MDCAppBarColorThemer.m",
+    "src/components/AppBar/src/ColorThemer/MaterialAppBar+ColorThemer.h",
     "src/components/AppBar/src/MDCAppBar.h",
     "src/components/AppBar/src/MDCAppBarContainerViewController.h",
     "src/components/AppBar/src/MDCAppBarContainerViewController.m",
+    "src/components/AppBar/src/MDCAppBarNavigationController.h",
+    "src/components/AppBar/src/MDCAppBarNavigationController.m",
     "src/components/AppBar/src/MDCAppBarViewController.h",
     "src/components/AppBar/src/MDCAppBarViewController.m",
     "src/components/AppBar/src/MaterialAppBar.h",
+    "src/components/AppBar/src/private/MaterialAppBarStrings.h",
+    "src/components/AppBar/src/private/MaterialAppBarStrings_table.h",
     "src/components/BottomSheet/src/MDCBottomSheetController.h",
     "src/components/BottomSheet/src/MDCBottomSheetController.m",
     "src/components/BottomSheet/src/MDCBottomSheetPresentationController.h",
@@ -163,6 +170,9 @@
     "src/components/Dialogs/src/private/MDCDialogShadowedView.m",
     "src/components/Dialogs/src/private/MaterialDialogsStrings.h",
     "src/components/Dialogs/src/private/MaterialDialogsStrings_table.h",
+    "src/components/FlexibleHeader/src/ColorThemer/MDCFlexibleHeaderColorThemer.h",
+    "src/components/FlexibleHeader/src/ColorThemer/MDCFlexibleHeaderColorThemer.m",
+    "src/components/FlexibleHeader/src/ColorThemer/MaterialFlexibleHeader+ColorThemer.h",
     "src/components/FlexibleHeader/src/MDCFlexibleHeaderContainerViewController.h",
     "src/components/FlexibleHeader/src/MDCFlexibleHeaderContainerViewController.m",
     "src/components/FlexibleHeader/src/MDCFlexibleHeaderView.h",
@@ -189,6 +199,9 @@
     "src/components/Ink/src/private/MDCLegacyInkLayer+Testing.h",
     "src/components/Ink/src/private/MDCLegacyInkLayer.h",
     "src/components/Ink/src/private/MDCLegacyInkLayer.m",
+    "src/components/NavigationBar/src/ColorThemer/MDCNavigationBarColorThemer.h",
+    "src/components/NavigationBar/src/ColorThemer/MDCNavigationBarColorThemer.m",
+    "src/components/NavigationBar/src/ColorThemer/MaterialNavigationBar+ColorThemer.h",
     "src/components/NavigationBar/src/MDCNavigationBar.h",
     "src/components/NavigationBar/src/MDCNavigationBar.m",
     "src/components/NavigationBar/src/MaterialNavigationBar.h",
@@ -309,12 +322,16 @@
     "src/components/ActivityIndicator/src",
     "src/components/AnimationTiming/src",
     "src/components/AppBar/src",
+    "src/components/AppBar/src/ColorThemer",
     "src/components/BottomSheet/src",
     "src/components/ButtonBar/src",
     "src/components/Buttons/src/ButtonThemer",
     "src/components/Buttons/src/ColorThemer",
     "src/components/Buttons/src/TypographyThemer",
+    "src/components/FlexibleHeader/src",
+    "src/components/FlexibleHeader/src/ColorThemer",
     "src/components/NavigationBar/src",
+    "src/components/NavigationBar/src/ColorThemer",
     "src/components/OverlayWindow/src",
     "src/components/private/Math/src",
     "src/components/private/Application/src",
@@ -376,6 +393,16 @@
 _locales = [ "en" ]
 
 foreach(locale, _locales) {
+  bundle_data("material_app_bar_bundle_$locale") {
+    visibility = [ ":material_app_bar_bundle" ]
+    sources = [
+      "src/components/AppBar/src/MaterialAppBar.bundle/Resources/$locale.lproj/MaterialAppBar.strings",
+    ]
+    outputs = [
+      "{{bundle_resources_dir}}/MaterialAppBar.bundle/Resources/$locale.lproj/{{source_file_part}}",
+    ]
+  }
+
   bundle_data("material_collections_bundle_$locale") {
     visibility = [ ":material_collections_bundle" ]
     sources = [
diff --git a/ios/web/public/BUILD.gn b/ios/web/public/BUILD.gn
index 65cce83..097b467e 100644
--- a/ios/web/public/BUILD.gn
+++ b/ios/web/public/BUILD.gn
@@ -65,7 +65,6 @@
     "web_client.h",
     "web_kit_constants.h",
     "web_state/context_menu_params.h",
-    "web_state/form_activity_params.h",
     "web_state/global_web_state_observer.h",
     "web_state/js/crw_js_injection_evaluator.h",
     "web_state/js/crw_js_injection_manager.h",
diff --git a/ios/web/public/test/fakes/crw_test_web_state_observer.mm b/ios/web/public/test/fakes/crw_test_web_state_observer.mm
index 0909c01..8d9763d 100644
--- a/ios/web/public/test/fakes/crw_test_web_state_observer.mm
+++ b/ios/web/public/test/fakes/crw_test_web_state_observer.mm
@@ -16,8 +16,6 @@
 #endif
 
 namespace web {
-TestFormActivityInfo::TestFormActivityInfo() {}
-TestFormActivityInfo::~TestFormActivityInfo() = default;
 TestUpdateFaviconUrlCandidatesInfo::TestUpdateFaviconUrlCandidatesInfo() {}
 TestUpdateFaviconUrlCandidatesInfo::~TestUpdateFaviconUrlCandidatesInfo() =
     default;
diff --git a/ios/web/public/test/fakes/test_web_state_observer_util.h b/ios/web/public/test/fakes/test_web_state_observer_util.h
index 7bdc738..d8fad7bf 100644
--- a/ios/web/public/test/fakes/test_web_state_observer_util.h
+++ b/ios/web/public/test/fakes/test_web_state_observer_util.h
@@ -9,7 +9,6 @@
 
 #include "ios/web/public/favicon_url.h"
 #include "ios/web/public/load_committed_details.h"
-#include "ios/web/public/web_state/form_activity_params.h"
 #include "url/gurl.h"
 
 namespace web {
@@ -87,22 +86,6 @@
   WebState* web_state;
 };
 
-// Arguments passed to |DocumentSubmitted|.
-struct TestSubmitDocumentInfo {
-  WebState* web_state;
-  std::string form_name;
-  bool user_initiated;
-  bool is_main_frame;
-};
-
-// Arguments passed to |FormActivityRegistered|.
-struct TestFormActivityInfo {
-  TestFormActivityInfo();
-  ~TestFormActivityInfo();
-  WebState* web_state;
-  FormActivityParams form_activity;
-};
-
 // Arguments passed to |FaviconUrlUpdated|.
 struct TestUpdateFaviconUrlCandidatesInfo {
   TestUpdateFaviconUrlCandidatesInfo();
diff --git a/ios/web/web_state/BUILD.gn b/ios/web/web_state/BUILD.gn
index ca6aed1..72d185b2 100644
--- a/ios/web/web_state/BUILD.gn
+++ b/ios/web/web_state/BUILD.gn
@@ -158,7 +158,6 @@
     "context_menu_params.mm",
     "context_menu_params_utils.h",
     "context_menu_params_utils.mm",
-    "form_activity_params.cc",
   ]
 
   configs += [ "//build/config/compiler:enable_arc" ]
diff --git a/ios/web_view/internal/autofill/cwv_autofill_controller.mm b/ios/web_view/internal/autofill/cwv_autofill_controller.mm
index be0c728..c920fad 100644
--- a/ios/web_view/internal/autofill/cwv_autofill_controller.mm
+++ b/ios/web_view/internal/autofill/cwv_autofill_controller.mm
@@ -17,9 +17,9 @@
 #import "components/autofill/ios/browser/js_autofill_manager.h"
 #import "components/autofill/ios/browser/js_suggestion_manager.h"
 #import "components/autofill/ios/form_util/form_activity_observer_bridge.h"
+#include "components/autofill/ios/form_util/form_activity_params.h"
 #include "components/browser_sync/profile_sync_service.h"
 #include "components/keyed_service/core/service_access_type.h"
-#include "ios/web/public/web_state/form_activity_params.h"
 #import "ios/web/public/web_state/js/crw_js_injection_receiver.h"
 #import "ios/web/public/web_state/web_state_observer_bridge.h"
 #include "ios/web_view/internal/app/application_context.h"
@@ -345,7 +345,7 @@
 #pragma mark - CRWWebStateObserver
 
 - (void)webState:(web::WebState*)webState
-    didRegisterFormActivity:(const web::FormActivityParams&)params {
+    didRegisterFormActivity:(const autofill::FormActivityParams&)params {
   DCHECK_EQ(_webState, webState);
 
   [_JSSuggestionManager inject];
diff --git a/ios/web_view/internal/autofill/cwv_autofill_controller_unittest.mm b/ios/web_view/internal/autofill/cwv_autofill_controller_unittest.mm
index d9ed27d..62192db 100644
--- a/ios/web_view/internal/autofill/cwv_autofill_controller_unittest.mm
+++ b/ios/web_view/internal/autofill/cwv_autofill_controller_unittest.mm
@@ -15,13 +15,13 @@
 #import "components/autofill/ios/browser/fake_js_autofill_manager.h"
 #import "components/autofill/ios/browser/form_suggestion.h"
 #import "components/autofill/ios/browser/js_suggestion_manager.h"
+#include "components/autofill/ios/form_util/form_activity_params.h"
 #import "components/autofill/ios/form_util/form_activity_tab_helper.h"
 #import "components/autofill/ios/form_util/test_form_activity_tab_helper.h"
 #import "ios/web/public/test/fakes/crw_test_js_injection_receiver.h"
 #import "ios/web/public/test/fakes/test_web_state.h"
 #include "ios/web/public/test/test_web_thread_bundle.h"
 #include "ios/web/public/web_client.h"
-#include "ios/web/public/web_state/form_activity_params.h"
 #import "ios/web_view/internal/autofill/cwv_autofill_suggestion_internal.h"
 #include "ios/web_view/internal/web_view_browser_state.h"
 #import "ios/web_view/public/cwv_autofill_controller_delegate.h"
@@ -208,7 +208,7 @@
                                    formName:kTestFormName
                                       value:kTestFieldValue];
 
-      web::FormActivityParams params;
+      autofill::FormActivityParams params;
       params.form_name = base::SysNSStringToUTF8(kTestFormName);
       params.field_name = base::SysNSStringToUTF8(kTestFieldName);
       params.field_identifier = base::SysNSStringToUTF8(kTestFieldIdentifier);
@@ -235,7 +235,7 @@
                                    formName:kTestFormName
                                       value:kTestFieldValue];
 
-      web::FormActivityParams params;
+      autofill::FormActivityParams params;
       params.form_name = base::SysNSStringToUTF8(kTestFormName);
       params.field_name = base::SysNSStringToUTF8(kTestFieldName);
       params.field_identifier = base::SysNSStringToUTF8(kTestFieldIdentifier);
@@ -261,7 +261,7 @@
                                  formName:kTestFormName
                                     value:kTestFieldValue];
 
-    web::FormActivityParams params;
+    autofill::FormActivityParams params;
     params.form_name = base::SysNSStringToUTF8(kTestFormName);
     params.field_name = base::SysNSStringToUTF8(kTestFieldName);
     params.field_identifier = base::SysNSStringToUTF8(kTestFieldIdentifier);
diff --git a/media/capture/video/chromeos/camera_device_delegate.cc b/media/capture/video/chromeos/camera_device_delegate.cc
index a8ccd53..86e37c9 100644
--- a/media/capture/video/chromeos/camera_device_delegate.cc
+++ b/media/capture/video/chromeos/camera_device_delegate.cc
@@ -11,6 +11,7 @@
 
 #include "base/numerics/ranges.h"
 #include "base/posix/safe_strerror.h"
+#include "base/trace_event/trace_event.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/capture/mojom/image_capture_types.h"
 #include "media/capture/video/blob_utils.h"
@@ -619,6 +620,10 @@
     cros::mojom::Camera3CaptureRequestPtr request,
     base::OnceCallback<void(int32_t)> callback) {
   DCHECK(ipc_task_runner_->BelongsToCurrentThread());
+  for (const auto& output_buffer : request->output_buffers) {
+    TRACE_EVENT2("camera", "Capture Request", "frame_number",
+                 request->frame_number, "stream_id", output_buffer->stream_id);
+  }
 
   if (device_context_->GetState() != CameraDeviceContext::State::kCapturing) {
     DCHECK_EQ(device_context_->GetState(),
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
index ade9c3e..202e420c 100644
--- a/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
+++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl.cc
@@ -18,6 +18,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/synchronization/waitable_event.h"
+#include "base/trace_event/trace_event.h"
 #include "mojo/public/cpp/platform/named_platform_channel.h"
 #include "mojo/public/cpp/platform/platform_channel.h"
 #include "mojo/public/cpp/platform/socket_utils_posix.h"
@@ -155,7 +156,11 @@
 
 CameraHalDispatcherImpl::CameraHalDispatcherImpl()
     : proxy_thread_("CameraProxyThread"),
-      blocking_io_thread_("CameraBlockingIOThread") {}
+      blocking_io_thread_("CameraBlockingIOThread") {
+  // This event is for adding camera category to categories list.
+  TRACE_EVENT0("camera", "CameraHalDispatcherImpl");
+  base::trace_event::TraceLog::GetInstance()->AddEnabledStateObserver(this);
+}
 
 CameraHalDispatcherImpl::~CameraHalDispatcherImpl() {
   VLOG(1) << "Stopping CameraHalDispatcherImpl...";
@@ -166,6 +171,7 @@
     proxy_thread_.Stop();
   }
   blocking_io_thread_.Stop();
+  base::trace_event::TraceLog::GetInstance()->RemoveEnabledStateObserver(this);
   VLOG(1) << "CameraHalDispatcherImpl stopped";
 }
 
@@ -212,6 +218,20 @@
   jea_factory_.Run(std::move(jea_request));
 }
 
+void CameraHalDispatcherImpl::OnTraceLogEnabled() {
+  proxy_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&CameraHalDispatcherImpl::OnTraceLogEnabledOnProxyThread,
+                     base::Unretained(this)));
+}
+
+void CameraHalDispatcherImpl::OnTraceLogDisabled() {
+  proxy_task_runner_->PostTask(
+      FROM_HERE,
+      base::BindOnce(&CameraHalDispatcherImpl::OnTraceLogDisabledOnProxyThread,
+                     base::Unretained(this)));
+}
+
 void CameraHalDispatcherImpl::CreateSocket(base::WaitableEvent* started) {
   DCHECK(blocking_io_task_runner_->BelongsToCurrentThread());
 
@@ -381,4 +401,24 @@
   binding_set_.CloseAllBindings();
 }
 
+void CameraHalDispatcherImpl::OnTraceLogEnabledOnProxyThread() {
+  DCHECK(proxy_task_runner_->BelongsToCurrentThread());
+  if (!camera_hal_server_) {
+    return;
+  }
+  bool camera_event_enabled = false;
+  TRACE_EVENT_CATEGORY_GROUP_ENABLED("camera", &camera_event_enabled);
+  if (camera_event_enabled) {
+    camera_hal_server_->SetTracingEnabled(true);
+  }
+}
+
+void CameraHalDispatcherImpl::OnTraceLogDisabledOnProxyThread() {
+  DCHECK(proxy_task_runner_->BelongsToCurrentThread());
+  if (!camera_hal_server_) {
+    return;
+  }
+  camera_hal_server_->SetTracingEnabled(false);
+}
+
 }  // namespace media
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl.h b/media/capture/video/chromeos/camera_hal_dispatcher_impl.h
index 1eecadc..02cd8fa 100644
--- a/media/capture/video/chromeos/camera_hal_dispatcher_impl.h
+++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl.h
@@ -44,7 +44,8 @@
 // For general documentation about the CameraHalDispater Mojo interface see the
 // comments in mojo/cros_camera_service.mojom.
 class CAPTURE_EXPORT CameraHalDispatcherImpl final
-    : public cros::mojom::CameraHalDispatcher {
+    : public cros::mojom::CameraHalDispatcher,
+      public base::trace_event::TraceLog::EnabledStateObserver {
  public:
   static CameraHalDispatcherImpl* GetInstance();
 
@@ -63,6 +64,10 @@
   void GetJpegEncodeAccelerator(
       media::mojom::JpegEncodeAcceleratorRequest jea_request) final;
 
+  // base::trace_event::TraceLog::EnabledStateObserver implementation.
+  void OnTraceLogEnabled() final;
+  void OnTraceLogDisabled() final;
+
  private:
   friend struct base::DefaultSingletonTraits<CameraHalDispatcherImpl>;
   // Allow the test to construct the class directly.
@@ -95,6 +100,9 @@
 
   void StopOnProxyThread();
 
+  void OnTraceLogEnabledOnProxyThread();
+  void OnTraceLogDisabledOnProxyThread();
+
   base::ScopedFD proxy_fd_;
   base::ScopedFD cancel_pipe_;
 
diff --git a/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc b/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc
index f552085..8e263c1 100644
--- a/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc
+++ b/media/capture/video/chromeos/camera_hal_dispatcher_impl_unittest.cc
@@ -34,6 +34,8 @@
   MOCK_METHOD1(DoCreateChannel,
                void(cros::mojom::CameraModuleRequest& camera_module_request));
 
+  MOCK_METHOD1(SetTracingEnabled, void(bool enabled));
+
   cros::mojom::CameraHalServerPtrInfo GetInterfacePtrInfo() {
     cros::mojom::CameraHalServerPtrInfo camera_hal_server_ptr_info;
     cros::mojom::CameraHalServerRequest camera_hal_server_request =
diff --git a/media/capture/video/chromeos/mojo/cros_camera_service.mojom b/media/capture/video/chromeos/mojo/cros_camera_service.mojom
index 4c6e8aa0..0d8b4ff 100644
--- a/media/capture/video/chromeos/mojo/cros_camera_service.mojom
+++ b/media/capture/video/chromeos/mojo/cros_camera_service.mojom
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// Next min version: 3
+// Next min version: 4
 
 module cros.mojom;
 
@@ -38,13 +38,17 @@
 
 // The CrOS camera HAL v3 Mojo server.
 //
-// Next method ID: 1
+// Next method ID: 2
 interface CameraHalServer {
   // A caller calls CreateChannel to create a new Mojo channel to the camera
   // HAL v3 adapter.  Upon successfully binding of |camera_module_request|, the
   // caller will have a established Mojo channel to the camera HAL v3 adapter
   // process.
   CreateChannel@0(CameraModule& camera_module_request);
+
+  // Enable or disable tracing.
+  [MinVersion=3]
+  SetTracingEnabled@1(bool enabled);
 };
 
 // The CrOS camera HAL v3 Mojo client.
diff --git a/media/capture/video/chromeos/stream_buffer_manager.cc b/media/capture/video/chromeos/stream_buffer_manager.cc
index 9d542494..8a0e234 100644
--- a/media/capture/video/chromeos/stream_buffer_manager.cc
+++ b/media/capture/video/chromeos/stream_buffer_manager.cc
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/posix/safe_strerror.h"
+#include "base/trace_event/trace_event.h"
 #include "media/capture/video/chromeos/camera_buffer_factory.h"
 #include "media/capture/video/chromeos/camera_device_context.h"
 #include "media/capture/video/chromeos/camera_metadata_utils.h"
@@ -579,6 +580,7 @@
   }
 
   for (const auto& iter : stream_context_) {
+    TRACE_EVENT1("camera", "Capture Result", "frame_number", frame_number);
     SubmitCaptureResultIfComplete(frame_number, iter.first);
   }
 }
diff --git a/media/capture/video/chromeos/video_capture_device_chromeos_halv3.cc b/media/capture/video/chromeos/video_capture_device_chromeos_halv3.cc
index a7e16cdb..4639836 100644
--- a/media/capture/video/chromeos/video_capture_device_chromeos_halv3.cc
+++ b/media/capture/video/chromeos/video_capture_device_chromeos_halv3.cc
@@ -12,6 +12,7 @@
 #include "base/location.h"
 #include "base/synchronization/waitable_event.h"
 #include "base/threading/platform_thread.h"
+#include "base/trace_event/trace_event.h"
 #include "chromeos/dbus/dbus_thread_manager.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/capture/video/chromeos/camera_device_context.h"
@@ -61,7 +62,7 @@
     std::unique_ptr<Client> client) {
   DCHECK(capture_task_runner_->BelongsToCurrentThread());
   DCHECK(!camera_device_delegate_);
-
+  TRACE_EVENT0("camera", "Start Device");
   if (!camera_device_ipc_thread_.Start()) {
     std::string error_msg = "Failed to start device thread";
     LOG(ERROR) << error_msg;
diff --git a/media/gpu/jpeg_decode_accelerator_unittest.cc b/media/gpu/jpeg_decode_accelerator_unittest.cc
index 280bfc86..b43a401d 100644
--- a/media/gpu/jpeg_decode_accelerator_unittest.cc
+++ b/media/gpu/jpeg_decode_accelerator_unittest.cc
@@ -140,6 +140,84 @@
   size_t output_size;
 };
 
+// Global singleton to hold on to common data and other user-defined options.
+class JpegDecodeAcceleratorTestEnvironment : public ::testing::Environment {
+ public:
+  JpegDecodeAcceleratorTestEnvironment(
+      const base::FilePath::CharType* jpeg_filenames,
+      int perf_decode_times)
+      : perf_decode_times_(perf_decode_times ? perf_decode_times
+                                             : kDefaultPerfDecodeTimes),
+        user_jpeg_filenames_(jpeg_filenames ? jpeg_filenames
+                                            : kDefaultJpegFilename) {}
+  void SetUp() override;
+
+  // Creates and returns a FilePath for the pathless |name|. The current folder
+  // is used if |name| exists in it, otherwise //media/test/data is used.
+  base::FilePath GetOriginalOrTestDataFilePath(const std::string& name) {
+    LOG_ASSERT(std::find_if(name.begin(), name.end(),
+                            base::FilePath::IsSeparator) == name.end())
+        << name << " should be just a file name and not have a path";
+    const base::FilePath original_file_path = base::FilePath(name);
+    if (base::PathExists(original_file_path))
+      return original_file_path;
+    return GetTestDataFilePath(name);
+  }
+
+  // Used for InputSizeChange test case. The image size should be smaller than
+  // |kDefaultJpegFilename|.
+  std::unique_ptr<ParsedJpegImage> image_data_1280x720_black_;
+  // Used for ResolutionChange test case.
+  std::unique_ptr<ParsedJpegImage> image_data_640x368_black_;
+  // Used for testing some drivers which will align the output resolution to a
+  // multiple of 16. 640x360 will be aligned to 640x368.
+  std::unique_ptr<ParsedJpegImage> image_data_640x360_black_;
+  // Parsed data of "peach_pi-1280x720.jpg".
+  std::unique_ptr<ParsedJpegImage> image_data_1280x720_default_;
+  // Parsed data of failure image.
+  std::unique_ptr<ParsedJpegImage> image_data_invalid_;
+  // Parsed data for images with at least one odd dimension.
+  std::vector<std::unique_ptr<ParsedJpegImage>> image_data_odd_;
+  // Parsed data from command line.
+  std::vector<std::unique_ptr<ParsedJpegImage>> image_data_user_;
+  // Decode times for performance measurement.
+  int perf_decode_times_;
+
+ private:
+  const base::FilePath::CharType* user_jpeg_filenames_;
+};
+
+void JpegDecodeAcceleratorTestEnvironment::SetUp() {
+  image_data_1280x720_black_ = ParsedJpegImage::CreateBlackImage(1280, 720);
+  image_data_640x368_black_ = ParsedJpegImage::CreateBlackImage(640, 368);
+  image_data_640x360_black_ = ParsedJpegImage::CreateBlackImage(640, 360);
+
+  image_data_1280x720_default_ = ParsedJpegImage::CreateFromFile(
+      GetOriginalOrTestDataFilePath(kDefaultJpegFilename));
+
+  image_data_invalid_ =
+      std::make_unique<ParsedJpegImage>(base::FilePath("failure.jpg"));
+  image_data_invalid_->data_str.resize(100, 0);
+  image_data_invalid_->InitializeSizes(1280, 720);
+
+  // Load test images with at least one odd dimension.
+  for (const auto* filename : kOddJpegFilenames) {
+    const base::FilePath input_file = GetOriginalOrTestDataFilePath(filename);
+    auto image_data = ParsedJpegImage::CreateFromFile(input_file);
+    image_data_odd_.push_back(std::move(image_data));
+  }
+
+  // |user_jpeg_filenames_| may include many files and use ';' as delimiter.
+  std::vector<base::FilePath::StringType> filenames = base::SplitString(
+      user_jpeg_filenames_, base::FilePath::StringType(1, ';'),
+      base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
+  for (const auto& filename : filenames) {
+    const base::FilePath input_file = GetOriginalOrTestDataFilePath(filename);
+    auto image_data = ParsedJpegImage::CreateFromFile(input_file);
+    image_data_user_.push_back(std::move(image_data));
+  }
+}
+
 enum ClientState {
   CS_CREATED,
   CS_INITIALIZED,
@@ -442,84 +520,6 @@
   return true;
 }
 
-// Global singleton to hold on to common data and other user-defined options.
-class JpegDecodeAcceleratorTestEnvironment : public ::testing::Environment {
- public:
-  JpegDecodeAcceleratorTestEnvironment(
-      const base::FilePath::CharType* jpeg_filenames,
-      int perf_decode_times)
-      : perf_decode_times_(perf_decode_times ? perf_decode_times
-                                             : kDefaultPerfDecodeTimes),
-        user_jpeg_filenames_(jpeg_filenames ? jpeg_filenames
-                                            : kDefaultJpegFilename) {}
-  void SetUp() override;
-
-  // Creates and returns a FilePath for the pathless |name|. The current folder
-  // is used if |name| exists in it, otherwise //media/test/data is used.
-  base::FilePath GetOriginalOrTestDataFilePath(const std::string& name) {
-    LOG_ASSERT(std::find_if(name.begin(), name.end(),
-                            base::FilePath::IsSeparator) == name.end())
-        << name << " should be just a file name and not have a path";
-    const base::FilePath original_file_path = base::FilePath(name);
-    if (base::PathExists(original_file_path))
-      return original_file_path;
-    return GetTestDataFilePath(name);
-  }
-
-  // Used for InputSizeChange test case. The image size should be smaller than
-  // |kDefaultJpegFilename|.
-  std::unique_ptr<ParsedJpegImage> image_data_1280x720_black_;
-  // Used for ResolutionChange test case.
-  std::unique_ptr<ParsedJpegImage> image_data_640x368_black_;
-  // Used for testing some drivers which will align the output resolution to a
-  // multiple of 16. 640x360 will be aligned to 640x368.
-  std::unique_ptr<ParsedJpegImage> image_data_640x360_black_;
-  // Parsed data of "peach_pi-1280x720.jpg".
-  std::unique_ptr<ParsedJpegImage> image_data_1280x720_default_;
-  // Parsed data of failure image.
-  std::unique_ptr<ParsedJpegImage> image_data_invalid_;
-  // Parsed data for images with at least one odd dimension.
-  std::vector<std::unique_ptr<ParsedJpegImage>> image_data_odd_;
-  // Parsed data from command line.
-  std::vector<std::unique_ptr<ParsedJpegImage>> image_data_user_;
-  // Decode times for performance measurement.
-  int perf_decode_times_;
-
- private:
-  const base::FilePath::CharType* user_jpeg_filenames_;
-};
-
-void JpegDecodeAcceleratorTestEnvironment::SetUp() {
-  image_data_1280x720_black_ = ParsedJpegImage::CreateBlackImage(1280, 720);
-  image_data_640x368_black_ = ParsedJpegImage::CreateBlackImage(640, 368);
-  image_data_640x360_black_ = ParsedJpegImage::CreateBlackImage(640, 360);
-
-  image_data_1280x720_default_ = ParsedJpegImage::CreateFromFile(
-      GetOriginalOrTestDataFilePath(kDefaultJpegFilename));
-
-  image_data_invalid_ =
-      std::make_unique<ParsedJpegImage>(base::FilePath("failure.jpg"));
-  image_data_invalid_->data_str.resize(100, 0);
-  image_data_invalid_->InitializeSizes(1280, 720);
-
-  // Load test images with at least one odd dimension.
-  for (const auto* filename : kOddJpegFilenames) {
-    const base::FilePath input_file = GetOriginalOrTestDataFilePath(filename);
-    auto image_data = ParsedJpegImage::CreateFromFile(input_file);
-    image_data_odd_.push_back(std::move(image_data));
-  }
-
-  // |user_jpeg_filenames_| may include many files and use ';' as delimiter.
-  std::vector<base::FilePath::StringType> filenames = base::SplitString(
-      user_jpeg_filenames_, base::FilePath::StringType(1, ';'),
-      base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
-  for (const auto& filename : filenames) {
-    const base::FilePath input_file = GetOriginalOrTestDataFilePath(filename);
-    auto image_data = ParsedJpegImage::CreateFromFile(input_file);
-    image_data_user_.push_back(std::move(image_data));
-  }
-}
-
 // This class holds a |client| that will be deleted on |task_runner|. This is
 // necessary because |client->decoder_| expects to be destroyed on the thread on
 // which it was created.
diff --git a/media/gpu/vaapi/accelerated_video_encoder.cc b/media/gpu/vaapi/accelerated_video_encoder.cc
index 17e3236e..2600cab0 100644
--- a/media/gpu/vaapi/accelerated_video_encoder.cc
+++ b/media/gpu/vaapi/accelerated_video_encoder.cc
@@ -4,11 +4,20 @@
 
 #include "media/gpu/vaapi/accelerated_video_encoder.h"
 
+#include <algorithm>
+
 #include "media/base/video_frame.h"
 #include "media/video/video_encode_accelerator.h"
 
 namespace media {
 
+namespace {
+// The maximum size for bitstream buffer, which is chosen empirically for the
+// video smaller than 1080p.
+// TODO(akahuang): Refactor it when we support 4K encoding.
+constexpr size_t kMaxBitstreamBufferSizeInBytes = 2 * 1024 * 1024;  // 2MB
+}  // namespace
+
 AcceleratedVideoEncoder::EncodeJob::EncodeJob(
     scoped_refptr<VideoFrame> input_frame,
     bool keyframe,
@@ -54,4 +63,12 @@
   std::move(execute_callback_).Run();
 }
 
+size_t AcceleratedVideoEncoder::GetBitstreamBufferSize() const {
+  // The buffer size of uncompressed stream is a feasible estimation of the
+  // output buffer size. However, the estimation is loose in high resolution.
+  // Therefore we set an empirical upper bound.
+  size_t uncompressed_buffer_size = GetCodedSize().GetArea() * 3 / 2;
+  return std::min(uncompressed_buffer_size, kMaxBitstreamBufferSizeInBytes);
+}
+
 }  // namespace media
diff --git a/media/gpu/vaapi/accelerated_video_encoder.h b/media/gpu/vaapi/accelerated_video_encoder.h
index c9a9a39..4d7fa39c 100644
--- a/media/gpu/vaapi/accelerated_video_encoder.h
+++ b/media/gpu/vaapi/accelerated_video_encoder.h
@@ -136,7 +136,7 @@
 
   // Returns minimum size in bytes for bitstream buffers required to fit output
   // stream buffers produced.
-  virtual size_t GetBitstreamBufferSize() const = 0;
+  virtual size_t GetBitstreamBufferSize() const;
 
   // Returns maximum number of reference frames that may be used by the
   // encoder to encode one frame. The client should be able to provide up to
diff --git a/media/gpu/vaapi/h264_encoder.cc b/media/gpu/vaapi/h264_encoder.cc
index 7dc0540..a5919317 100644
--- a/media/gpu/vaapi/h264_encoder.cc
+++ b/media/gpu/vaapi/h264_encoder.cc
@@ -106,13 +106,6 @@
   return coded_size_;
 }
 
-size_t H264Encoder::GetBitstreamBufferSize() const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(!coded_size_.IsEmpty());
-
-  return coded_size_.GetArea();
-}
-
 size_t H264Encoder::GetMaxNumOfRefFrames() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
diff --git a/media/gpu/vaapi/h264_encoder.h b/media/gpu/vaapi/h264_encoder.h
index a86ee42..2d32081 100644
--- a/media/gpu/vaapi/h264_encoder.h
+++ b/media/gpu/vaapi/h264_encoder.h
@@ -102,7 +102,6 @@
   bool UpdateRates(const VideoBitrateAllocation& bitrate_allocation,
                    uint32_t framerate) override;
   gfx::Size GetCodedSize() const override;
-  size_t GetBitstreamBufferSize() const override;
   size_t GetMaxNumOfRefFrames() const override;
   bool PrepareEncodeJob(EncodeJob* encode_job) override;
 
diff --git a/media/gpu/vaapi/vaapi_video_encode_accelerator.cc b/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
index a6a033b..69c0856 100644
--- a/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
+++ b/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
@@ -54,8 +54,6 @@
 // Need 2 surfaces for each frame: one for input data and one for
 // reconstructed picture, which is later used for reference.
 constexpr size_t kNumSurfacesPerFrame = 2;
-// TODO(owenlin): Adjust the value after b/71367113 is fixed
-constexpr size_t kExtraOutputBufferSizeInBytes = 32768;
 
 constexpr int kDefaultFramerate = 30;
 
@@ -306,8 +304,7 @@
   }
 
   coded_size_ = encoder_->GetCodedSize();
-  output_buffer_byte_size_ =
-      encoder_->GetBitstreamBufferSize() + kExtraOutputBufferSizeInBytes;
+  output_buffer_byte_size_ = encoder_->GetBitstreamBufferSize();
   const size_t max_ref_frames = encoder_->GetMaxNumOfRefFrames();
   // Use at least kMinNumFramesInFlight if encoder requested less for
   // pipeline depth.
diff --git a/media/gpu/vaapi/vaapi_wrapper.cc b/media/gpu/vaapi/vaapi_wrapper.cc
index 39420e3..9aab6d0d 100644
--- a/media/gpu/vaapi/vaapi_wrapper.cc
+++ b/media/gpu/vaapi/vaapi_wrapper.cc
@@ -1258,7 +1258,8 @@
       DCHECK(buffer_segment->buf);
 
       if (buffer_segment->size > target_size) {
-        LOG(ERROR) << "Insufficient output buffer size";
+        LOG(ERROR) << "Insufficient output buffer size: " << target_size
+                   << ", the buffer segment size: " << buffer_segment->size;
         break;
       }
 
diff --git a/media/gpu/vaapi/vp8_encoder.cc b/media/gpu/vaapi/vp8_encoder.cc
index 2463f23..b7df863c 100644
--- a/media/gpu/vaapi/vp8_encoder.cc
+++ b/media/gpu/vaapi/vp8_encoder.cc
@@ -78,13 +78,6 @@
   return coded_size_;
 }
 
-size_t VP8Encoder::GetBitstreamBufferSize() const {
-  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
-  DCHECK(!coded_size_.IsEmpty());
-
-  return coded_size_.GetArea();
-}
-
 size_t VP8Encoder::GetMaxNumOfRefFrames() const {
   DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 
diff --git a/media/gpu/vaapi/vp8_encoder.h b/media/gpu/vaapi/vp8_encoder.h
index a5f9e5e..0b9b0e88 100644
--- a/media/gpu/vaapi/vp8_encoder.h
+++ b/media/gpu/vaapi/vp8_encoder.h
@@ -79,7 +79,6 @@
   bool UpdateRates(const VideoBitrateAllocation& bitrate_allocation,
                    uint32_t framerate) override;
   gfx::Size GetCodedSize() const override;
-  size_t GetBitstreamBufferSize() const override;
   size_t GetMaxNumOfRefFrames() const override;
   bool PrepareEncodeJob(EncodeJob* encode_job) override;
 
diff --git a/media/gpu/windows/d3d11_picture_buffer.cc b/media/gpu/windows/d3d11_picture_buffer.cc
index 645b819d3..24dc5d401 100644
--- a/media/gpu/windows/d3d11_picture_buffer.cc
+++ b/media/gpu/windows/d3d11_picture_buffer.cc
@@ -38,7 +38,9 @@
                                        size_t level)
     : target_(target), size_(size), level_(level) {}
 
-D3D11PictureBuffer::~D3D11PictureBuffer() {}
+D3D11PictureBuffer::~D3D11PictureBuffer() {
+  // TODO(liberato): post destruction of |gpu_resources_| to the gpu thread.
+}
 
 bool D3D11PictureBuffer::Init(
     base::RepeatingCallback<gpu::CommandBufferStub*()> get_stub_cb,
@@ -71,6 +73,7 @@
   // device for decoding.  Sharing seems not to work very well.  Otherwise, we
   // would create the texture with KEYED_MUTEX and NTHANDLE, then send along
   // a handle that we get from |texture| as an IDXGIResource1.
+  // TODO(liberato): this should happen on the gpu thread.
   gpu_resources_ = std::make_unique<GpuResources>();
   if (!gpu_resources_->Init(std::move(get_stub_cb), level_,
                             std::move(mailboxes), target_, size_, texture,
diff --git a/media/gpu/windows/d3d11_video_decoder.cc b/media/gpu/windows/d3d11_video_decoder.cc
index 628ebb581..27c23d7 100644
--- a/media/gpu/windows/d3d11_video_decoder.cc
+++ b/media/gpu/windows/d3d11_video_decoder.cc
@@ -10,41 +10,16 @@
 #include "base/callback.h"
 #include "base/metrics/histogram_macros.h"
 #include "media/base/bind_to_current_loop.h"
+#include "media/base/cdm_context.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/media_log.h"
 #include "media/base/video_codecs.h"
 #include "media/base/video_decoder_config.h"
 #include "media/base/video_frame.h"
+#include "media/base/video_util.h"
+#include "media/gpu/windows/d3d11_picture_buffer.h"
 #include "media/gpu/windows/d3d11_video_decoder_impl.h"
-
-namespace {
-
-// Check |weak_ptr| and run |cb| with |args| if it's non-null.
-template <typename T, typename... Args>
-void CallbackOnProperThread(base::WeakPtr<T> weak_ptr,
-                            base::Callback<void(Args...)> cb,
-                            Args... args) {
-  if (weak_ptr.get())
-    cb.Run(args...);
-}
-
-// Given a callback, |cb|, return another callback that will call |cb| after
-// switching to the thread that BindToCurrent.... is called on.  We will check
-// |weak_ptr| on the current thread.  This is different than just calling
-// BindToCurrentLoop because we'll check the weak ptr.  If |cb| is some method
-// of |T|, then one can use BindToCurrentLoop directly.  However, in our case,
-// we have some unrelated callback that we'd like to call only if we haven't
-// been destroyed yet.  I suppose this could also just be a method:
-// template<CB, ...> D3D11VideoDecoder::CallSomeCallback(CB, ...) that's bound
-// via BindToCurrentLoop directly.
-template <typename T, typename... Args>
-base::Callback<void(Args...)> BindToCurrentThreadIfWeakPtr(
-    base::WeakPtr<T> weak_ptr,
-    base::Callback<void(Args...)> cb) {
-  return media::BindToCurrentLoop(
-      base::Bind(&CallbackOnProperThread<T, Args...>, weak_ptr, cb));
-}
-}  // namespace
+#include "ui/gl/gl_angle_util_win.h"
 
 namespace media {
 
@@ -65,7 +40,8 @@
       new D3D11VideoDecoder(std::move(gpu_task_runner), std::move(media_log),
                             gpu_preferences, gpu_workarounds,
                             std::make_unique<D3D11VideoDecoderImpl>(
-                                std::move(cloned_media_log), get_stub_cb)));
+                                std::move(cloned_media_log), get_stub_cb),
+                            get_stub_cb));
 }
 
 D3D11VideoDecoder::D3D11VideoDecoder(
@@ -73,14 +49,18 @@
     std::unique_ptr<MediaLog> media_log,
     const gpu::GpuPreferences& gpu_preferences,
     const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
-    std::unique_ptr<D3D11VideoDecoderImpl> impl)
+    std::unique_ptr<D3D11VideoDecoderImpl> impl,
+    base::RepeatingCallback<gpu::CommandBufferStub*()> get_stub_cb)
     : media_log_(std::move(media_log)),
       impl_(std::move(impl)),
       impl_task_runner_(std::move(gpu_task_runner)),
       gpu_preferences_(gpu_preferences),
       gpu_workarounds_(gpu_workarounds),
       create_device_func_(base::BindRepeating(D3D11CreateDevice)),
+      get_stub_cb_(get_stub_cb),
       weak_factory_(this) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   impl_weak_ = impl_->GetWeakPtr();
 }
 
@@ -88,6 +68,8 @@
   // Post destruction to the main thread.  When this executes, it will also
   // cancel pending callbacks into |impl_| via |impl_weak_|.  Callbacks out
   // from |impl_| will be cancelled by |weak_factory_| when we return.
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   if (impl_task_runner_->RunsTasksInCurrentSequence())
     impl_.reset();
   else
@@ -105,15 +87,152 @@
     const InitCB& init_cb,
     const OutputCB& output_cb,
     const WaitingForDecryptionKeyCB& waiting_for_decryption_key_cb) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   if (!IsPotentiallySupported(config)) {
     DVLOG(3) << "D3D11 video decoder not supported for the config.";
     init_cb.Run(false);
     return;
   }
 
+  init_cb_ = init_cb;
+  output_cb_ = output_cb;
+  is_encrypted_ = config.is_encrypted();
+
+  D3D11VideoDecoderImpl::InitCB cb = base::BindOnce(
+      &D3D11VideoDecoder::OnGpuInitComplete, weak_factory_.GetWeakPtr());
+
+  D3D11VideoDecoderImpl::ReturnPictureBufferCB return_picture_buffer_cb =
+      base::BindRepeating(&D3D11VideoDecoder::ReceivePictureBufferFromClient,
+                          weak_factory_.GetWeakPtr());
+
+  // Initialize the video decoder.
+
+  // Use the ANGLE device, rather than create our own.  It would be nice if we
+  // could use our own device, and run on the mojo thread, but texture sharing
+  // seems to be difficult.
+  // TODO(liberato): take |device_| as input.
+  device_ = gl::QueryD3D11DeviceObjectFromANGLE();
+  device_->GetImmediateContext(device_context_.ReleaseAndGetAddressOf());
+
+  HRESULT hr;
+
+  // TODO(liberato): Handle cleanup better.  Also consider being less chatty in
+  // the logs, since this will fall back.
+  hr = device_context_.CopyTo(video_context_.ReleaseAndGetAddressOf());
+  if (!SUCCEEDED(hr)) {
+    NotifyError("Failed to get device context");
+    return;
+  }
+
+  hr = device_.CopyTo(video_device_.ReleaseAndGetAddressOf());
+  if (!SUCCEEDED(hr)) {
+    NotifyError("Failed to get video device");
+    return;
+  }
+
+  GUID needed_guid;
+  memcpy(&needed_guid, &D3D11_DECODER_PROFILE_H264_VLD_NOFGT,
+         sizeof(needed_guid));
+  GUID decoder_guid = {};
+
+  {
+    // Enumerate supported video profiles and look for the H264 profile.
+    bool found = false;
+    UINT profile_count = video_device_->GetVideoDecoderProfileCount();
+    for (UINT profile_idx = 0; profile_idx < profile_count; profile_idx++) {
+      GUID profile_id = {};
+      hr = video_device_->GetVideoDecoderProfile(profile_idx, &profile_id);
+      if (SUCCEEDED(hr) && (profile_id == needed_guid)) {
+        decoder_guid = profile_id;
+        found = true;
+        break;
+      }
+    }
+
+    if (!found) {
+      NotifyError("Did not find a supported profile");
+      return;
+    }
+  }
+
+  // TODO(liberato): dxva does this.  don't know if we need to.
+  Microsoft::WRL::ComPtr<ID3D11Multithread> multi_threaded;
+  hr = device_->QueryInterface(IID_PPV_ARGS(&multi_threaded));
+  if (!SUCCEEDED(hr)) {
+    NotifyError("Failed to query ID3D11Multithread");
+    return;
+  }
+  multi_threaded->SetMultithreadProtected(TRUE);
+
+  D3D11_VIDEO_DECODER_DESC desc = {};
+  desc.Guid = decoder_guid;
+  desc.SampleWidth = config.coded_size().width();
+  desc.SampleHeight = config.coded_size().height();
+  desc.OutputFormat = DXGI_FORMAT_NV12;
+  UINT config_count = 0;
+  hr = video_device_->GetVideoDecoderConfigCount(&desc, &config_count);
+  if (FAILED(hr) || config_count == 0) {
+    NotifyError("Failed to get video decoder config count");
+    return;
+  }
+
+  D3D11_VIDEO_DECODER_CONFIG dec_config = {};
+  bool found = false;
+  for (UINT i = 0; i < config_count; i++) {
+    hr = video_device_->GetVideoDecoderConfig(&desc, i, &dec_config);
+    if (FAILED(hr)) {
+      NotifyError("Failed to get decoder config");
+      return;
+    }
+    if (dec_config.ConfigBitstreamRaw == 2) {
+      found = true;
+      break;
+    }
+  }
+  if (!found) {
+    NotifyError("Failed to find decoder config");
+    return;
+  }
+
+  if (is_encrypted_)
+    dec_config.guidConfigBitstreamEncryption = D3D11_DECODER_ENCRYPTION_HW_CENC;
+
+  memcpy(&decoder_guid_, &decoder_guid, sizeof decoder_guid_);
+
+  Microsoft::WRL::ComPtr<ID3D11VideoDecoder> video_decoder;
+  hr = video_device_->CreateVideoDecoder(
+      &desc, &dec_config, video_decoder.ReleaseAndGetAddressOf());
+  if (!video_decoder.Get()) {
+    NotifyError("Failed to create a video decoder");
+    return;
+  }
+
+  CdmProxyContext* proxy_context = nullptr;
+#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
+  if (cdm_context)
+    proxy_context = cdm_context->GetCdmProxyContext();
+#endif
+
+  accelerated_video_decoder_ = std::make_unique<H264Decoder>(
+      std::make_unique<D3D11H264Accelerator>(this, media_log_.get(),
+                                             proxy_context, video_decoder,
+                                             video_device_, video_context_),
+      config.color_space_info());
+
+  // |cdm_context| could be null for clear playback.
+  if (cdm_context) {
+    new_key_callback_registration_ =
+        cdm_context->RegisterNewKeyCB(base::BindRepeating(
+            &D3D11VideoDecoder::NotifyNewKey, weak_factory_.GetWeakPtr()));
+  }
+
+  // Initialize the gpu side.  We wait until everything else is initialized,
+  // since we allow it to call us back re-entrantly to reduce latency.  Note
+  // that if we're not on the same thread, then we should probably post the
+  // call earlier, since re-entrancy won't be an issue.
   if (impl_task_runner_->RunsTasksInCurrentSequence()) {
-    impl_->Initialize(config, low_delay, cdm_context, init_cb, output_cb,
-                      waiting_for_decryption_key_cb);
+    impl_->Initialize(std::move(cb), std::move(return_picture_buffer_cb));
     return;
   }
 
@@ -121,56 +240,303 @@
   // the originals on some other thread.
   // Important but subtle note: base::Bind will copy |config_| since it's a
   // const ref.
-  // TODO(liberato): what's the lifetime of |cdm_context|?
   impl_task_runner_->PostTask(
       FROM_HERE,
-      base::BindOnce(
-          &VideoDecoder::Initialize, impl_weak_, config, low_delay, cdm_context,
-          BindToCurrentThreadIfWeakPtr(weak_factory_.GetWeakPtr(), init_cb),
-          BindToCurrentThreadIfWeakPtr(weak_factory_.GetWeakPtr(), output_cb),
-          BindToCurrentThreadIfWeakPtr(weak_factory_.GetWeakPtr(),
-                                       waiting_for_decryption_key_cb)));
+      base::BindOnce(&D3D11VideoDecoderImpl::Initialize, impl_weak_,
+                     BindToCurrentLoop(std::move(cb)),
+                     BindToCurrentLoop(std::move(return_picture_buffer_cb))));
+}
+
+void D3D11VideoDecoder::ReceivePictureBufferFromClient(
+    scoped_refptr<D3D11PictureBuffer> buffer) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  // We may decode into this buffer again.
+  // Note that |buffer| might no longer be in |picture_buffers_| if we've
+  // replaced them.  That's okay.
+  buffer->set_in_client_use(false);
+
+  // Also re-start decoding in case it was waiting for more pictures.
+  DoDecode();
+}
+
+void D3D11VideoDecoder::OnGpuInitComplete(bool success) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (!init_cb_) {
+    // We already failed, so just do nothing.
+    return;
+  }
+
+  if (!success) {
+    NotifyError("Gpu init failed");
+    return;
+  }
+
+  state_ = State::kRunning;
+  std::move(init_cb_).Run(true);
 }
 
 void D3D11VideoDecoder::Decode(scoped_refptr<DecoderBuffer> buffer,
                                const DecodeCB& decode_cb) {
-  if (impl_task_runner_->RunsTasksInCurrentSequence()) {
-    impl_->Decode(std::move(buffer), decode_cb);
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (state_ == State::kError) {
+    // TODO(liberato): consider posting, though it likely doesn't matter.
+    decode_cb.Run(DecodeStatus::DECODE_ERROR);
     return;
   }
 
-  impl_task_runner_->PostTask(
+  input_buffer_queue_.push_back(std::make_pair(std::move(buffer), decode_cb));
+  // Post, since we're not supposed to call back before this returns.  It
+  // probably doesn't matter since we're in the gpu process anyway.
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE,
-      base::BindOnce(
-          &VideoDecoder::Decode, impl_weak_, std::move(buffer),
-          BindToCurrentThreadIfWeakPtr(weak_factory_.GetWeakPtr(), decode_cb)));
+      base::BindOnce(&D3D11VideoDecoder::DoDecode, weak_factory_.GetWeakPtr()));
 }
 
-void D3D11VideoDecoder::Reset(const base::Closure& closure) {
-  if (impl_task_runner_->RunsTasksInCurrentSequence()) {
-    impl_->Reset(closure);
+void D3D11VideoDecoder::DoDecode() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (state_ != State::kRunning)
     return;
+
+  if (!current_buffer_) {
+    if (input_buffer_queue_.empty()) {
+      return;
+    }
+    current_buffer_ = std::move(input_buffer_queue_.front().first);
+    current_decode_cb_ = input_buffer_queue_.front().second;
+    input_buffer_queue_.pop_front();
+    if (current_buffer_->end_of_stream()) {
+      // Flush, then signal the decode cb once all pictures have been output.
+      current_buffer_ = nullptr;
+      if (!accelerated_video_decoder_->Flush()) {
+        // This will also signal error |current_decode_cb_|.
+        NotifyError("Flush failed");
+        return;
+      }
+      // Pictures out output synchronously during Flush.  Signal the decode
+      // cb now.
+      std::move(current_decode_cb_).Run(DecodeStatus::OK);
+      return;
+    }
+    // This must be after checking for EOS because there is no timestamp for an
+    // EOS buffer.
+    current_timestamp_ = current_buffer_->timestamp();
+
+    accelerated_video_decoder_->SetStream(-1, current_buffer_->data(),
+                                          current_buffer_->data_size(),
+                                          current_buffer_->decrypt_config());
   }
 
-  impl_task_runner_->PostTask(
-      FROM_HERE, base::BindOnce(&VideoDecoder::Reset, impl_weak_,
-                                BindToCurrentThreadIfWeakPtr(
-                                    weak_factory_.GetWeakPtr(), closure)));
+  while (true) {
+    // If we transition to the error state, then stop here.
+    if (state_ == State::kError)
+      return;
+
+    media::AcceleratedVideoDecoder::DecodeResult result =
+        accelerated_video_decoder_->Decode();
+    // TODO(liberato): switch + class enum.
+    if (result == media::AcceleratedVideoDecoder::kRanOutOfStreamData) {
+      current_buffer_ = nullptr;
+      std::move(current_decode_cb_).Run(DecodeStatus::OK);
+      break;
+    } else if (result == media::AcceleratedVideoDecoder::kRanOutOfSurfaces) {
+      // At this point, we know the picture size.
+      // If we haven't allocated picture buffers yet, then allocate some now.
+      // Otherwise, stop here.  We'll restart when a picture comes back.
+      if (picture_buffers_.size())
+        return;
+      CreatePictureBuffers();
+    } else if (result == media::AcceleratedVideoDecoder::kAllocateNewSurfaces) {
+      CreatePictureBuffers();
+    } else if (result == media::AcceleratedVideoDecoder::kTryAgain) {
+      state_ = State::kWaitingForNewKey;
+      // Note that another DoDecode() task would be posted in NotifyNewKey().
+      return;
+    } else {
+      LOG(ERROR) << "VDA Error " << result;
+      NotifyError("Accelerated decode failed");
+      return;
+    }
+  }
+
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&D3D11VideoDecoder::DoDecode, weak_factory_.GetWeakPtr()));
+}
+
+void D3D11VideoDecoder::Reset(const base::RepeatingClosure& closure) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  current_buffer_ = nullptr;
+  if (current_decode_cb_)
+    std::move(current_decode_cb_).Run(DecodeStatus::ABORTED);
+
+  for (auto& queue_pair : input_buffer_queue_)
+    queue_pair.second.Run(DecodeStatus::ABORTED);
+  input_buffer_queue_.clear();
+
+  // TODO(liberato): how do we signal an error?
+  accelerated_video_decoder_->Reset();
+  closure.Run();
 }
 
 bool D3D11VideoDecoder::NeedsBitstreamConversion() const {
-  // Wrong thread, but it's okay.
-  return impl_->NeedsBitstreamConversion();
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  return true;
 }
 
 bool D3D11VideoDecoder::CanReadWithoutStalling() const {
-  // Wrong thread, but it's okay.
-  return impl_->CanReadWithoutStalling();
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  return false;
 }
 
 int D3D11VideoDecoder::GetMaxDecodeRequests() const {
-  // Wrong thread, but it's okay.
-  return impl_->GetMaxDecodeRequests();
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  return 4;
+}
+
+void D3D11VideoDecoder::CreatePictureBuffers() {
+  // TODO(liberato): When we run off the gpu main thread, this call will need
+  // to signal success / failure asynchronously.  We'll need to transition into
+  // a "waiting for pictures" state, since D3D11PictureBuffer will post the gpu
+  // thread work.
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  // TODO(liberato): what's the minimum that we need for the decoder?
+  // the VDA requests 20.
+  const int num_buffers = 20;
+
+  gfx::Size size = accelerated_video_decoder_->GetPicSize();
+
+  // Create an array of |num_buffers| elements to back the PictureBuffers.
+  D3D11_TEXTURE2D_DESC texture_desc = {};
+  texture_desc.Width = size.width();
+  texture_desc.Height = size.height();
+  texture_desc.MipLevels = 1;
+  texture_desc.ArraySize = num_buffers;
+  texture_desc.Format = DXGI_FORMAT_NV12;
+  texture_desc.SampleDesc.Count = 1;
+  texture_desc.Usage = D3D11_USAGE_DEFAULT;
+  texture_desc.BindFlags = D3D11_BIND_DECODER | D3D11_BIND_SHADER_RESOURCE;
+  texture_desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
+  if (is_encrypted_)
+    texture_desc.MiscFlags |= D3D11_RESOURCE_MISC_HW_PROTECTED;
+
+  Microsoft::WRL::ComPtr<ID3D11Texture2D> out_texture;
+  HRESULT hr = device_->CreateTexture2D(&texture_desc, nullptr,
+                                        out_texture.ReleaseAndGetAddressOf());
+  if (!SUCCEEDED(hr)) {
+    NotifyError("Failed to create a Texture2D for PictureBuffers");
+    return;
+  }
+
+  // Drop any old pictures.
+  for (auto& buffer : picture_buffers_)
+    DCHECK(!buffer->in_picture_use());
+  picture_buffers_.clear();
+
+  // Create each picture buffer.
+  const int textures_per_picture = 2;  // From the VDA
+  for (size_t i = 0; i < num_buffers; i++) {
+    picture_buffers_.push_back(
+        new D3D11PictureBuffer(GL_TEXTURE_EXTERNAL_OES, size, i));
+    if (!picture_buffers_[i]->Init(get_stub_cb_, video_device_, out_texture,
+                                   decoder_guid_, textures_per_picture)) {
+      NotifyError("Unable to allocate PictureBuffer");
+      return;
+    }
+  }
+}
+
+D3D11PictureBuffer* D3D11VideoDecoder::GetPicture() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  for (auto& buffer : picture_buffers_) {
+    if (!buffer->in_client_use() && !buffer->in_picture_use()) {
+      buffer->timestamp_ = current_timestamp_;
+      return buffer.get();
+    }
+  }
+
+  return nullptr;
+}
+
+void D3D11VideoDecoder::OutputResult(D3D11PictureBuffer* buffer,
+                                     const VideoColorSpace& buffer_colorspace) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  buffer->set_in_client_use(true);
+
+  // Note: The pixel format doesn't matter.
+  gfx::Rect visible_rect(buffer->size());
+  // TODO(liberato): Pixel aspect ratio should come from the VideoDecoderConfig
+  // (except when it should come from the SPS).
+  // https://crbug.com/837337
+  double pixel_aspect_ratio = 1.0;
+  base::TimeDelta timestamp = buffer->timestamp_;
+  scoped_refptr<VideoFrame> frame = VideoFrame::WrapNativeTextures(
+      PIXEL_FORMAT_NV12, buffer->mailbox_holders(),
+      VideoFrame::ReleaseMailboxCB(), visible_rect.size(), visible_rect,
+      GetNaturalSize(visible_rect, pixel_aspect_ratio), timestamp);
+
+  // TODO(liberato): bind this to the gpu main thread.
+  frame->SetReleaseMailboxCB(media::BindToCurrentLoop(
+      base::BindOnce(&D3D11VideoDecoderImpl::OnMailboxReleased, impl_weak_,
+                     scoped_refptr<D3D11PictureBuffer>(buffer))));
+  frame->metadata()->SetBoolean(VideoFrameMetadata::POWER_EFFICIENT, true);
+  // For NV12, overlay is allowed by default. If the decoder is going to support
+  // non-NV12 textures, then this may have to be conditionally set. Also note
+  // that ALLOW_OVERLAY is required for encrypted video path.
+  frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true);
+
+  if (is_encrypted_) {
+    frame->metadata()->SetBoolean(VideoFrameMetadata::PROTECTED_VIDEO, true);
+    frame->metadata()->SetBoolean(VideoFrameMetadata::REQUIRE_OVERLAY, true);
+  }
+
+  frame->set_color_space(buffer_colorspace.ToGfxColorSpace());
+  output_cb_.Run(frame);
+}
+
+void D3D11VideoDecoder::NotifyNewKey() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
+  if (state_ != State::kWaitingForNewKey) {
+    // Note that this method may be called before DoDecode() because the key
+    // acquisition stack may be running independently of the media decoding
+    // stack. So if this isn't in kWaitingForNewKey state no "resuming" is
+    // required therefore no special action taken here.
+    return;
+  }
+
+  state_ = State::kRunning;
+  base::ThreadTaskRunnerHandle::Get()->PostTask(
+      FROM_HERE,
+      base::BindOnce(&D3D11VideoDecoder::DoDecode, weak_factory_.GetWeakPtr()));
+}
+
+void D3D11VideoDecoder::NotifyError(const char* reason) {
+  state_ = State::kError;
+  DLOG(ERROR) << reason;
+  if (media_log_) {
+    media_log_->AddEvent(media_log_->CreateStringEvent(
+        MediaLogEvent::MEDIA_ERROR_LOG_ENTRY, "error", reason));
+  }
+
+  if (init_cb_)
+    std::move(init_cb_).Run(false);
+
+  if (current_decode_cb_)
+    std::move(current_decode_cb_).Run(DecodeStatus::DECODE_ERROR);
+
+  for (auto& queue_pair : input_buffer_queue_)
+    queue_pair.second.Run(DecodeStatus::DECODE_ERROR);
 }
 
 void D3D11VideoDecoder::SetCreateDeviceCallbackForTesting(
@@ -180,6 +546,8 @@
 
 void D3D11VideoDecoder::SetWasSupportedReason(
     D3D11VideoNotSupportedReason enum_value) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   UMA_HISTOGRAM_ENUMERATION("Media.D3D11.WasVideoSupported", enum_value);
 
   const char* reason = nullptr;
@@ -213,6 +581,8 @@
 
 bool D3D11VideoDecoder::IsPotentiallySupported(
     const VideoDecoderConfig& config) {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+
   // TODO(liberato): All of this could be moved into MojoVideoDecoder, so that
   // it could run on the client side and save the IPC hop.
 
diff --git a/media/gpu/windows/d3d11_video_decoder.h b/media/gpu/windows/d3d11_video_decoder.h
index 93771b9b..2e12583 100644
--- a/media/gpu/windows/d3d11_video_decoder.h
+++ b/media/gpu/windows/d3d11_video_decoder.h
@@ -10,29 +10,35 @@
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
 #include "base/sequenced_task_runner.h"
 #include "base/single_thread_task_runner.h"
 #include "gpu/config/gpu_driver_bug_workarounds.h"
 #include "gpu/config/gpu_preferences.h"
-#include "gpu/ipc/service/command_buffer_stub.h"
+#include "media/base/callback_registry.h"
 #include "media/base/video_decoder.h"
 #include "media/gpu/media_gpu_export.h"
 #include "media/gpu/windows/d3d11_create_device_cb.h"
+#include "media/gpu/windows/d3d11_h264_accelerator.h"
+
+namespace gpu {
+class CommandBufferStub;
+}  // namespace gpu
 
 namespace media {
 
+class D3D11PictureBuffer;
 class D3D11VideoDecoderImpl;
 class D3D11VideoDecoderTest;
 class MediaLog;
 
-// Thread-hopping implementation of D3D11VideoDecoder.  It's meant to run on
-// a random thread, and hop to the gpu main thread.  It does this so that it
-// can use the D3D context etc.  What should really happen is that we should
-// get (or share with other D3D11VideoDecoder instances) our own context, and
-// just share the D3D texture with the main thread's context.  However, for
-// now, it's easier to hop threads.
-class MEDIA_GPU_EXPORT D3D11VideoDecoder : public VideoDecoder {
+// Video decoder that uses D3D11 directly.  It is intended that this class will
+// run the decoder on whatever thread it lives on.  However, at the moment, it
+// only works if it's on the gpu main thread.
+class MEDIA_GPU_EXPORT D3D11VideoDecoder : public VideoDecoder,
+                                           public D3D11VideoDecoderClient {
  public:
+  // |get_stub_cb| must be called from |gpu_task_runner|.
   static std::unique_ptr<VideoDecoder> Create(
       scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
       std::unique_ptr<MediaLog> media_log,
@@ -51,11 +57,16 @@
       const WaitingForDecryptionKeyCB& waiting_for_decryption_key_cb) override;
   void Decode(scoped_refptr<DecoderBuffer> buffer,
               const DecodeCB& decode_cb) override;
-  void Reset(const base::Closure& closure) override;
+  void Reset(const base::RepeatingClosure& closure) override;
   bool NeedsBitstreamConversion() const override;
   bool CanReadWithoutStalling() const override;
   int GetMaxDecodeRequests() const override;
 
+  // D3D11VideoDecoderClient implementation.
+  D3D11PictureBuffer* GetPicture() override;
+  void OutputResult(D3D11PictureBuffer* buffer,
+                    const VideoColorSpace& buffer_colorspace) override;
+
   // Return false |config| definitely isn't going to work, so that we can fail
   // init without bothering with a thread hop.
   bool IsPotentiallySupported(const VideoDecoderConfig& config);
@@ -72,11 +83,27 @@
  private:
   friend class D3D11VideoDecoderTest;
 
-  D3D11VideoDecoder(scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
-                    std::unique_ptr<MediaLog> media_log,
-                    const gpu::GpuPreferences& gpu_preferences,
-                    const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
-                    std::unique_ptr<D3D11VideoDecoderImpl> impl);
+  D3D11VideoDecoder(
+      scoped_refptr<base::SingleThreadTaskRunner> gpu_task_runner,
+      std::unique_ptr<MediaLog> media_log,
+      const gpu::GpuPreferences& gpu_preferences,
+      const gpu::GpuDriverBugWorkarounds& gpu_workarounds,
+      std::unique_ptr<D3D11VideoDecoderImpl> impl,
+      base::RepeatingCallback<gpu::CommandBufferStub*()> get_stub_cb);
+
+  // Receive |buffer|, that is now unused by the client.
+  void ReceivePictureBufferFromClient(scoped_refptr<D3D11PictureBuffer> buffer);
+
+  // Called when the gpu side of initialization is complete.
+  void OnGpuInitComplete(bool success);
+
+  // Run the decoder loop.
+  void DoDecode();
+
+  // Create new PictureBuffers.  Currently, this completes synchronously, but
+  // really should have an async interface since it must do some work on the gpu
+  // main thread.
+  void CreatePictureBuffers();
 
   enum class D3D11VideoNotSupportedReason {
     kVideoIsSupported = 0,
@@ -104,16 +131,39 @@
 
   std::unique_ptr<MediaLog> media_log_;
 
+  enum class State {
+    // Initializing resources required to create a codec.
+    kInitializing,
+    // Initialization has completed and we're running. This is the only state
+    // in which |codec_| might be non-null. If |codec_| is null, a codec
+    // creation is pending.
+    kRunning,
+    // The decoder cannot make progress because it doesn't have the key to
+    // decrypt the buffer. Waiting for a new key to be available.
+    // This should only be transitioned from kRunning, and should only
+    // transition to kRunning.
+    kWaitingForNewKey,
+    // A fatal error occurred. A terminal state.
+    kError,
+  };
+
   // Record a UMA about why IsPotentiallySupported returned false, or that it
   // returned true.  Also will add a MediaLog entry, etc.
   void SetWasSupportedReason(D3D11VideoNotSupportedReason enum_value);
 
+  // Callback to notify that new usable key is available.
+  void NotifyNewKey();
+
+  // Enter the kError state.  This will fail any pending |init_cb_| and / or
+  // pending decode as well.
+  void NotifyError(const char* reason);
+
   // The implementation, which we trampoline to the impl thread.
   // This must be freed on the impl thread.
   std::unique_ptr<D3D11VideoDecoderImpl> impl_;
 
   // Weak ptr to |impl_|, which we use for callbacks.
-  base::WeakPtr<VideoDecoder> impl_weak_;
+  base::WeakPtr<D3D11VideoDecoderImpl> impl_weak_;
 
   // Task runner for |impl_|.  This must be the GPU main thread.
   scoped_refptr<base::SequencedTaskRunner> impl_task_runner_;
@@ -121,8 +171,44 @@
   gpu::GpuPreferences gpu_preferences_;
   gpu::GpuDriverBugWorkarounds gpu_workarounds_;
 
+  // During init, these will be set.
+  InitCB init_cb_;
+  OutputCB output_cb_;
+  bool is_encrypted_ = false;
+
   D3D11CreateDeviceCB create_device_func_;
 
+  Microsoft::WRL::ComPtr<ID3D11Device> device_;
+  Microsoft::WRL::ComPtr<ID3D11DeviceContext> device_context_;
+  Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device_;
+  Microsoft::WRL::ComPtr<ID3D11VideoContext1> video_context_;
+
+  std::unique_ptr<AcceleratedVideoDecoder> accelerated_video_decoder_;
+
+  GUID decoder_guid_;
+
+  std::list<std::pair<scoped_refptr<DecoderBuffer>, DecodeCB>>
+      input_buffer_queue_;
+  scoped_refptr<DecoderBuffer> current_buffer_;
+  DecodeCB current_decode_cb_;
+  base::TimeDelta current_timestamp_;
+
+  // Callback registration to keep the new key callback registered.
+  std::unique_ptr<CallbackRegistration> new_key_callback_registration_;
+
+  // Must be called on the gpu main thread.  So, don't call it from here, since
+  // we don't know what thread we're on.
+  base::RepeatingCallback<gpu::CommandBufferStub*()> get_stub_cb_;
+
+  // It would be nice to unique_ptr these, but we give a ref to the VideoFrame
+  // so that the texture is retained until the mailbox is opened.
+  std::vector<scoped_refptr<D3D11PictureBuffer>> picture_buffers_;
+
+  State state_ = State::kInitializing;
+
+  // Entire class should be single-sequence.
+  SEQUENCE_CHECKER(sequence_checker_);
+
   base::WeakPtrFactory<D3D11VideoDecoder> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(D3D11VideoDecoder);
diff --git a/media/gpu/windows/d3d11_video_decoder_impl.cc b/media/gpu/windows/d3d11_video_decoder_impl.cc
index eed52b2..4d9440e4 100644
--- a/media/gpu/windows/d3d11_video_decoder_impl.cc
+++ b/media/gpu/windows/d3d11_video_decoder_impl.cc
@@ -4,23 +4,11 @@
 
 #include "media/gpu/windows/d3d11_video_decoder_impl.h"
 
-#include <d3d11_4.h>
-
-#include "base/threading/sequenced_task_runner_handle.h"
-#include "gpu/command_buffer/service/mailbox_manager.h"
+#include "gpu/command_buffer/common/sync_token.h"
 #include "gpu/command_buffer/service/scheduler.h"
-#include "gpu/command_buffer/service/texture_manager.h"
 #include "gpu/ipc/service/gpu_channel.h"
-#include "media/base/bind_to_current_loop.h"
-#include "media/base/cdm_context.h"
-#include "media/base/decoder_buffer.h"
 #include "media/base/media_log.h"
-#include "media/base/video_decoder_config.h"
-#include "media/base/video_frame.h"
-#include "media/base/video_util.h"
 #include "media/gpu/windows/d3d11_picture_buffer.h"
-#include "ui/gl/gl_angle_util_win.h"
-#include "ui/gl/gl_bindings.h"
 
 namespace media {
 
@@ -37,377 +25,48 @@
     base::RepeatingCallback<gpu::CommandBufferStub*()> get_stub_cb)
     : media_log_(std::move(media_log)),
       get_stub_cb_(get_stub_cb),
-      weak_factory_(this) {}
+      weak_factory_(this) {
+  // May be called from any thread.
+}
 
 D3D11VideoDecoderImpl::~D3D11VideoDecoderImpl() {
-  // TODO(liberato): be sure to clear |picture_buffers_| on the main thread.
-  // For now, we always run on the main thread anyway.
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   if (stub_ && !wait_sequence_id_.is_null())
     stub_->channel()->scheduler()->DestroySequence(wait_sequence_id_);
 }
 
-std::string D3D11VideoDecoderImpl::GetDisplayName() const {
-  NOTREACHED() << "Nobody should ask D3D11VideoDecoderImpl for its name";
-  return "D3D11VideoDecoderImpl";
-}
-
 void D3D11VideoDecoderImpl::Initialize(
-    const VideoDecoderConfig& config,
-    bool low_delay,
-    CdmContext* cdm_context,
-    const InitCB& init_cb,
-    const OutputCB& output_cb,
-    const WaitingForDecryptionKeyCB& waiting_for_decryption_key_cb) {
-  init_cb_ = init_cb;
-  output_cb_ = output_cb;
-  is_encrypted_ = config.is_encrypted();
+    InitCB init_cb,
+    ReturnPictureBufferCB return_picture_buffer_cb) {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   stub_ = get_stub_cb_.Run();
   if (!MakeContextCurrent(stub_)) {
-    NotifyError("Failed to get decoder stub");
+    const char* reason = "Failed to get decoder stub";
+    DLOG(ERROR) << reason;
+    if (media_log_) {
+      media_log_->AddEvent(media_log_->CreateStringEvent(
+          MediaLogEvent::MEDIA_ERROR_LOG_ENTRY, "error", reason));
+    }
+    std::move(init_cb).Run(false);
     return;
   }
+
+  return_picture_buffer_cb_ = std::move(return_picture_buffer_cb);
+
   // TODO(liberato): see GpuVideoFrameFactory.
   // stub_->AddDestructionObserver(this);
   wait_sequence_id_ = stub_->channel()->scheduler()->CreateSequence(
       gpu::SchedulingPriority::kNormal);
 
-  // Use the ANGLE device, rather than create our own.  It would be nice if we
-  // could use our own device, and run on the mojo thread, but texture sharing
-  // seems to be difficult.
-  device_ = gl::QueryD3D11DeviceObjectFromANGLE();
-  device_->GetImmediateContext(device_context_.ReleaseAndGetAddressOf());
-
-  HRESULT hr;
-
-  // TODO(liberato): Handle cleanup better.  Also consider being less chatty in
-  // the logs, since this will fall back.
-  hr = device_context_.CopyTo(video_context_.ReleaseAndGetAddressOf());
-  if (!SUCCEEDED(hr)) {
-    NotifyError("Failed to get device context");
-    return;
-  }
-
-  hr = device_.CopyTo(video_device_.ReleaseAndGetAddressOf());
-  if (!SUCCEEDED(hr)) {
-    NotifyError("Failed to get video device");
-    return;
-  }
-
-  GUID needed_guid;
-  memcpy(&needed_guid, &D3D11_DECODER_PROFILE_H264_VLD_NOFGT,
-         sizeof(needed_guid));
-  GUID decoder_guid = {};
-
-  {
-    // Enumerate supported video profiles and look for the H264 profile.
-    bool found = false;
-    UINT profile_count = video_device_->GetVideoDecoderProfileCount();
-    for (UINT profile_idx = 0; profile_idx < profile_count; profile_idx++) {
-      GUID profile_id = {};
-      hr = video_device_->GetVideoDecoderProfile(profile_idx, &profile_id);
-      if (SUCCEEDED(hr) && (profile_id == needed_guid)) {
-        decoder_guid = profile_id;
-        found = true;
-        break;
-      }
-    }
-
-    if (!found) {
-      NotifyError("Did not find a supported profile");
-      return;
-    }
-  }
-
-  // TODO(liberato): dxva does this.  don't know if we need to.
-  Microsoft::WRL::ComPtr<ID3D11Multithread> multi_threaded;
-  hr = device_->QueryInterface(IID_PPV_ARGS(&multi_threaded));
-  if (!SUCCEEDED(hr)) {
-    NotifyError("Failed to query ID3D11Multithread");
-    return;
-  }
-  multi_threaded->SetMultithreadProtected(TRUE);
-
-  D3D11_VIDEO_DECODER_DESC desc = {};
-  desc.Guid = decoder_guid;
-  desc.SampleWidth = config.coded_size().width();
-  desc.SampleHeight = config.coded_size().height();
-  desc.OutputFormat = DXGI_FORMAT_NV12;
-  UINT config_count = 0;
-  hr = video_device_->GetVideoDecoderConfigCount(&desc, &config_count);
-  if (FAILED(hr) || config_count == 0) {
-    NotifyError("Failed to get video decoder config count");
-    return;
-  }
-
-  D3D11_VIDEO_DECODER_CONFIG dec_config = {};
-  bool found = false;
-  for (UINT i = 0; i < config_count; i++) {
-    hr = video_device_->GetVideoDecoderConfig(&desc, i, &dec_config);
-    if (FAILED(hr)) {
-      NotifyError("Failed to get decoder config");
-      return;
-    }
-    if (dec_config.ConfigBitstreamRaw == 2) {
-      found = true;
-      break;
-    }
-  }
-  if (!found) {
-    NotifyError("Failed to find decoder config");
-    return;
-  }
-
-  if (is_encrypted_)
-    dec_config.guidConfigBitstreamEncryption = D3D11_DECODER_ENCRYPTION_HW_CENC;
-
-  memcpy(&decoder_guid_, &decoder_guid, sizeof decoder_guid_);
-
-  Microsoft::WRL::ComPtr<ID3D11VideoDecoder> video_decoder;
-  hr = video_device_->CreateVideoDecoder(
-      &desc, &dec_config, video_decoder.ReleaseAndGetAddressOf());
-  if (!video_decoder.Get()) {
-    NotifyError("Failed to create a video decoder");
-    return;
-  }
-
-  CdmProxyContext* proxy_context = nullptr;
-#if BUILDFLAG(ENABLE_LIBRARY_CDMS)
-  if (cdm_context)
-    proxy_context = cdm_context->GetCdmProxyContext();
-#endif
-
-  accelerated_video_decoder_ = std::make_unique<H264Decoder>(
-      std::make_unique<D3D11H264Accelerator>(this, media_log_.get(),
-                                             proxy_context, video_decoder,
-                                             video_device_, video_context_),
-      config.color_space_info());
-
-  // |cdm_context| could be null for clear playback.
-  if (cdm_context) {
-    new_key_callback_registration_ =
-        cdm_context->RegisterNewKeyCB(base::BindRepeating(
-            &D3D11VideoDecoderImpl::NotifyNewKey, weak_factory_.GetWeakPtr()));
-  }
-
-  state_ = State::kRunning;
-  std::move(init_cb_).Run(true);
-}
-
-void D3D11VideoDecoderImpl::Decode(scoped_refptr<DecoderBuffer> buffer,
-                                   const DecodeCB& decode_cb) {
-  if (state_ == State::kError) {
-    // TODO(liberato): consider posting, though it likely doesn't matter.
-    decode_cb.Run(DecodeStatus::DECODE_ERROR);
-    return;
-  }
-
-  input_buffer_queue_.push_back(std::make_pair(std::move(buffer), decode_cb));
-  // Post, since we're not supposed to call back before this returns.  It
-  // probably doesn't matter since we're in the gpu process anyway.
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::Bind(&D3D11VideoDecoderImpl::DoDecode, weak_factory_.GetWeakPtr()));
-}
-
-void D3D11VideoDecoderImpl::DoDecode() {
-  if (state_ != State::kRunning)
-    return;
-
-  if (!current_buffer_) {
-    if (input_buffer_queue_.empty()) {
-      return;
-    }
-    current_buffer_ = std::move(input_buffer_queue_.front().first);
-    current_decode_cb_ = input_buffer_queue_.front().second;
-    input_buffer_queue_.pop_front();
-    if (current_buffer_->end_of_stream()) {
-      // Flush, then signal the decode cb once all pictures have been output.
-      current_buffer_ = nullptr;
-      if (!accelerated_video_decoder_->Flush()) {
-        // This will also signal error |current_decode_cb_|.
-        NotifyError("Flush failed");
-        return;
-      }
-      // Pictures out output synchronously during Flush.  Signal the decode
-      // cb now.
-      std::move(current_decode_cb_).Run(DecodeStatus::OK);
-      return;
-    }
-    // This must be after checking for EOS because there is no timestamp for an
-    // EOS buffer.
-    current_timestamp_ = current_buffer_->timestamp();
-
-    accelerated_video_decoder_->SetStream(-1, current_buffer_->data(),
-                                          current_buffer_->data_size(),
-                                          current_buffer_->decrypt_config());
-  }
-
-  while (true) {
-    // If we transition to the error state, then stop here.
-    if (state_ == State::kError)
-      return;
-
-    media::AcceleratedVideoDecoder::DecodeResult result =
-        accelerated_video_decoder_->Decode();
-    // TODO(liberato): switch + class enum.
-    if (result == media::AcceleratedVideoDecoder::kRanOutOfStreamData) {
-      current_buffer_ = nullptr;
-      std::move(current_decode_cb_).Run(DecodeStatus::OK);
-      break;
-    } else if (result == media::AcceleratedVideoDecoder::kRanOutOfSurfaces) {
-      // At this point, we know the picture size.
-      // If we haven't allocated picture buffers yet, then allocate some now.
-      // Otherwise, stop here.  We'll restart when a picture comes back.
-      if (picture_buffers_.size())
-        return;
-      CreatePictureBuffers();
-    } else if (result == media::AcceleratedVideoDecoder::kAllocateNewSurfaces) {
-      CreatePictureBuffers();
-    } else if (result == media::AcceleratedVideoDecoder::kTryAgain) {
-      state_ = State::kWaitingForNewKey;
-      // Note that another DoDecode() task would be posted in NotifyNewKey().
-      return;
-    } else {
-      LOG(ERROR) << "VDA Error " << result;
-      NotifyError("Accelerated decode failed");
-      return;
-    }
-  }
-
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::Bind(&D3D11VideoDecoderImpl::DoDecode, weak_factory_.GetWeakPtr()));
-}
-
-void D3D11VideoDecoderImpl::Reset(const base::Closure& closure) {
-  current_buffer_ = nullptr;
-  if (current_decode_cb_)
-    std::move(current_decode_cb_).Run(DecodeStatus::ABORTED);
-
-  for (auto& queue_pair : input_buffer_queue_)
-    queue_pair.second.Run(DecodeStatus::ABORTED);
-  input_buffer_queue_.clear();
-
-  // TODO(liberato): how do we signal an error?
-  accelerated_video_decoder_->Reset();
-  closure.Run();
-}
-
-bool D3D11VideoDecoderImpl::NeedsBitstreamConversion() const {
-  // This is called from multiple threads.
-  return true;
-}
-
-bool D3D11VideoDecoderImpl::CanReadWithoutStalling() const {
-  // This is called from multiple threads.
-  return false;
-}
-
-int D3D11VideoDecoderImpl::GetMaxDecodeRequests() const {
-  // This is called from multiple threads.
-  return 4;
-}
-
-void D3D11VideoDecoderImpl::CreatePictureBuffers() {
-  // TODO(liberato): what's the minimum that we need for the decoder?
-  // the VDA requests 20.
-  const int num_buffers = 20;
-
-  gfx::Size size = accelerated_video_decoder_->GetPicSize();
-
-  // Create an array of |num_buffers| elements to back the PictureBuffers.
-  D3D11_TEXTURE2D_DESC texture_desc = {};
-  texture_desc.Width = size.width();
-  texture_desc.Height = size.height();
-  texture_desc.MipLevels = 1;
-  texture_desc.ArraySize = num_buffers;
-  texture_desc.Format = DXGI_FORMAT_NV12;
-  texture_desc.SampleDesc.Count = 1;
-  texture_desc.Usage = D3D11_USAGE_DEFAULT;
-  texture_desc.BindFlags = D3D11_BIND_DECODER | D3D11_BIND_SHADER_RESOURCE;
-  texture_desc.MiscFlags = D3D11_RESOURCE_MISC_SHARED;
-  if (is_encrypted_)
-    texture_desc.MiscFlags |= D3D11_RESOURCE_MISC_HW_PROTECTED;
-
-  Microsoft::WRL::ComPtr<ID3D11Texture2D> out_texture;
-  HRESULT hr = device_->CreateTexture2D(&texture_desc, nullptr,
-                                        out_texture.ReleaseAndGetAddressOf());
-  if (!SUCCEEDED(hr)) {
-    NotifyError("Failed to create a Texture2D for PictureBuffers");
-    return;
-  }
-
-  // Drop any old pictures.
-  for (auto& buffer : picture_buffers_)
-    DCHECK(!buffer->in_picture_use());
-  picture_buffers_.clear();
-
-  // Create each picture buffer.
-  const int textures_per_picture = 2;  // From the VDA
-  for (size_t i = 0; i < num_buffers; i++) {
-    picture_buffers_.push_back(
-        new D3D11PictureBuffer(GL_TEXTURE_EXTERNAL_OES, size, i));
-    if (!picture_buffers_[i]->Init(get_stub_cb_, video_device_, out_texture,
-                                   decoder_guid_, textures_per_picture)) {
-      NotifyError("Unable to allocate PictureBuffer");
-      return;
-    }
-  }
-}
-
-D3D11PictureBuffer* D3D11VideoDecoderImpl::GetPicture() {
-  for (auto& buffer : picture_buffers_) {
-    if (!buffer->in_client_use() && !buffer->in_picture_use()) {
-      buffer->timestamp_ = current_timestamp_;
-      return buffer.get();
-    }
-  }
-
-  return nullptr;
-}
-
-void D3D11VideoDecoderImpl::OutputResult(
-    D3D11PictureBuffer* buffer,
-    const VideoColorSpace& buffer_colorspace) {
-  buffer->set_in_client_use(true);
-
-  // Note: The pixel format doesn't matter.
-  gfx::Rect visible_rect(buffer->size());
-  // TODO(liberato): Pixel aspect ratio should come from the VideoDecoderConfig
-  // (except when it should come from the SPS).
-  // https://crbug.com/837337
-  double pixel_aspect_ratio = 1.0;
-  base::TimeDelta timestamp = buffer->timestamp_;
-  scoped_refptr<VideoFrame> frame = VideoFrame::WrapNativeTextures(
-      PIXEL_FORMAT_NV12, buffer->mailbox_holders(),
-      VideoFrame::ReleaseMailboxCB(), visible_rect.size(), visible_rect,
-      GetNaturalSize(visible_rect, pixel_aspect_ratio), timestamp);
-
-  frame->SetReleaseMailboxCB(media::BindToCurrentLoop(base::BindOnce(
-      &D3D11VideoDecoderImpl::OnMailboxReleased, weak_factory_.GetWeakPtr(),
-      scoped_refptr<D3D11PictureBuffer>(buffer))));
-  frame->metadata()->SetBoolean(VideoFrameMetadata::POWER_EFFICIENT, true);
-  // For NV12, overlay is allowed by default. If the decoder is going to support
-  // non-NV12 textures, then this may have to be conditionally set. Also note
-  // that ALLOW_OVERLAY is required for encrypted video path.
-  frame->metadata()->SetBoolean(VideoFrameMetadata::ALLOW_OVERLAY, true);
-
-  if (is_encrypted_) {
-    frame->metadata()->SetBoolean(VideoFrameMetadata::PROTECTED_VIDEO, true);
-    frame->metadata()->SetBoolean(VideoFrameMetadata::REQUIRE_OVERLAY, true);
-  }
-
-  frame->set_color_space(buffer_colorspace.ToGfxColorSpace());
-  output_cb_.Run(frame);
+  std::move(init_cb).Run(true);
 }
 
 void D3D11VideoDecoderImpl::OnMailboxReleased(
     scoped_refptr<D3D11PictureBuffer> buffer,
     const gpu::SyncToken& sync_token) {
-  // Note that |buffer| might no longer be in |picture_buffers_| if we've
-  // replaced them.  That's okay.
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
   stub_->channel()->scheduler()->ScheduleTask(gpu::Scheduler::Task(
       wait_sequence_id_,
@@ -418,52 +77,14 @@
 
 void D3D11VideoDecoderImpl::OnSyncTokenReleased(
     scoped_refptr<D3D11PictureBuffer> buffer) {
-  // Note that |buffer| might no longer be in |picture_buffers_|.
-  buffer->set_in_client_use(false);
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
 
-  // Also re-start decoding in case it was waiting for more pictures.
-  // TODO(liberato): there might be something pending already.  we should
-  // probably check.
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE,
-      base::BindOnce(&D3D11VideoDecoderImpl::DoDecode, GetWeakPtr()));
+  return_picture_buffer_cb_.Run(std::move(buffer));
 }
 
 base::WeakPtr<D3D11VideoDecoderImpl> D3D11VideoDecoderImpl::GetWeakPtr() {
+  // May be called from any thread.
   return weak_factory_.GetWeakPtr();
 }
 
-void D3D11VideoDecoderImpl::NotifyNewKey() {
-  if (state_ != State::kWaitingForNewKey) {
-    // Note that this method may be called before DoDecode() because the key
-    // acquisition stack may be running independently of the media decoding
-    // stack. So if this isn't in kWaitingForNewKey state no "resuming" is
-    // required therefore no special action taken here.
-    return;
-  }
-
-  state_ = State::kRunning;
-  base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(&D3D11VideoDecoderImpl::DoDecode,
-                                weak_factory_.GetWeakPtr()));
-}
-
-void D3D11VideoDecoderImpl::NotifyError(const char* reason) {
-  state_ = State::kError;
-  DLOG(ERROR) << reason;
-  if (media_log_) {
-    media_log_->AddEvent(media_log_->CreateStringEvent(
-        MediaLogEvent::MEDIA_ERROR_LOG_ENTRY, "error", reason));
-  }
-
-  if (init_cb_)
-    std::move(init_cb_).Run(false);
-
-  if (current_decode_cb_)
-    std::move(current_decode_cb_).Run(DecodeStatus::DECODE_ERROR);
-
-  for (auto& queue_pair : input_buffer_queue_)
-    queue_pair.second.Run(DecodeStatus::DECODE_ERROR);
-}
-
 }  // namespace media
diff --git a/media/gpu/windows/d3d11_video_decoder_impl.h b/media/gpu/windows/d3d11_video_decoder_impl.h
index f6350bc..c765a69c 100644
--- a/media/gpu/windows/d3d11_video_decoder_impl.h
+++ b/media/gpu/windows/d3d11_video_decoder_impl.h
@@ -13,122 +13,71 @@
 #include <string>
 #include <tuple>
 
+#include "base/callback.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/threading/thread_checker.h"
 #include "gpu/command_buffer/service/sequence_id.h"
-#include "gpu/ipc/service/command_buffer_stub.h"
-#include "media/base/callback_registry.h"
-#include "media/base/video_decoder.h"
-#include "media/base/video_decoder_config.h"
-#include "media/gpu/gles2_decoder_helper.h"
 #include "media/gpu/media_gpu_export.h"
-#include "media/gpu/windows/d3d11_h264_accelerator.h"
-#include "media/gpu/windows/output_with_release_mailbox_cb.h"
+
+namespace gpu {
+class CommandBufferStub;
+struct SyncToken;
+}  // namespace gpu
 
 namespace media {
 
 class MediaLog;
+class D3D11PictureBuffer;
 
-class MEDIA_GPU_EXPORT D3D11VideoDecoderImpl : public VideoDecoder,
-                                               public D3D11VideoDecoderClient {
+// Does the gpu main thread work for D3D11VideoDecoder.  Except as noted, this
+// class lives on the GPU main thread.
+// TODO(liberato): Rename this class as a follow-on to this refactor.
+class MEDIA_GPU_EXPORT D3D11VideoDecoderImpl {
  public:
+  // May be constructed on any thread.
   explicit D3D11VideoDecoderImpl(
       std::unique_ptr<MediaLog> media_log,
       base::RepeatingCallback<gpu::CommandBufferStub*()> get_stub_cb);
-  ~D3D11VideoDecoderImpl() override;
+  virtual ~D3D11VideoDecoderImpl();
 
-  // VideoDecoder implementation:
-  std::string GetDisplayName() const override;
-  void Initialize(
-      const VideoDecoderConfig& config,
-      bool low_delay,
-      CdmContext* cdm_context,
-      const InitCB& init_cb,
-      const OutputCB& output_cb,
-      const WaitingForDecryptionKeyCB& waiting_for_decryption_key_cb) override;
-  void Decode(scoped_refptr<DecoderBuffer> buffer,
-              const DecodeCB& decode_cb) override;
-  void Reset(const base::Closure& closure) override;
-  bool NeedsBitstreamConversion() const override;
-  bool CanReadWithoutStalling() const override;
-  int GetMaxDecodeRequests() const override;
+  using InitCB = base::OnceCallback<void(bool success)>;
 
-  // D3D11VideoDecoderClient implementation.
-  D3D11PictureBuffer* GetPicture() override;
-  void OutputResult(D3D11PictureBuffer* buffer,
-                    const VideoColorSpace& buffer_colorspace) override;
+  // Returns a picture buffer that's no longer in use by the client.
+  using ReturnPictureBufferCB =
+      base::RepeatingCallback<void(scoped_refptr<D3D11PictureBuffer>)>;
+
+  // We will call back |init_cb| with the init status.  |try_decoding_cb| should
+  // try to re-start decoding.  We'll call this when we do something that might
+  // allow decoding to make progress, such as reclaim a picture buffer.
+  virtual void Initialize(InitCB init_cb,
+                          ReturnPictureBufferCB return_picture_buffer_cb);
+
+  // Called when the VideoFrame that uses |buffer| is freed.
+  void OnMailboxReleased(scoped_refptr<D3D11PictureBuffer> buffer,
+                         const gpu::SyncToken& sync_token);
 
   // Return a weak ptr, since D3D11VideoDecoder constructs callbacks for us.
+  // May be called from any thread.
   base::WeakPtr<D3D11VideoDecoderImpl> GetWeakPtr();
 
  private:
-  enum class State {
-    // Initializing resources required to create a codec.
-    kInitializing,
-    // Initialization has completed and we're running. This is the only state
-    // in which |codec_| might be non-null. If |codec_| is null, a codec
-    // creation is pending.
-    kRunning,
-    // The decoder cannot make progress because it doesn't have the key to
-    // decrypt the buffer. Waiting for a new key to be available.
-    // This should only be transitioned from kRunning, and should only
-    // transition to kRunning.
-    kWaitingForNewKey,
-    // A fatal error occurred. A terminal state.
-    kError,
-  };
-
-  void DoDecode();
-  void CreatePictureBuffers();
-
-  void OnMailboxReleased(scoped_refptr<D3D11PictureBuffer> buffer,
-                         const gpu::SyncToken& sync_token);
   void OnSyncTokenReleased(scoped_refptr<D3D11PictureBuffer> buffer);
 
-  // Callback to notify that new usable key is available.
-  void NotifyNewKey();
-
-  // Enter the kError state.  This will fail any pending |init_cb_| and / or
-  // pending decode as well.
-  void NotifyError(const char* reason);
-
   std::unique_ptr<MediaLog> media_log_;
 
   base::RepeatingCallback<gpu::CommandBufferStub*()> get_stub_cb_;
   gpu::CommandBufferStub* stub_ = nullptr;
 
-  Microsoft::WRL::ComPtr<ID3D11Device> device_;
-  Microsoft::WRL::ComPtr<ID3D11DeviceContext> device_context_;
-  Microsoft::WRL::ComPtr<ID3D11VideoDevice> video_device_;
-  Microsoft::WRL::ComPtr<ID3D11VideoContext1> video_context_;
-
-  std::unique_ptr<AcceleratedVideoDecoder> accelerated_video_decoder_;
-
-  GUID decoder_guid_;
-
-  std::list<std::pair<scoped_refptr<DecoderBuffer>, DecodeCB>>
-      input_buffer_queue_;
-  scoped_refptr<DecoderBuffer> current_buffer_;
-  DecodeCB current_decode_cb_;
-  base::TimeDelta current_timestamp_;
-
-  // During init, these will be set.
-  InitCB init_cb_;
-  OutputCB output_cb_;
-  bool is_encrypted_ = false;
-
-  // It would be nice to unique_ptr these, but we give a ref to the VideoFrame
-  // so that the texture is retained until the mailbox is opened.
-  std::vector<scoped_refptr<D3D11PictureBuffer>> picture_buffers_;
-
-  State state_ = State::kInitializing;
-
-  // Callback registration to keep the new key callback registered.
-  std::unique_ptr<CallbackRegistration> new_key_callback_registration_;
-
   // Wait sequence for sync points.
   gpu::SequenceId wait_sequence_id_;
 
+  // Called when we get a picture buffer back from the client.
+  ReturnPictureBufferCB return_picture_buffer_cb_;
+
+  // Has thread affinity -- must be run on the gpu main thread.
+  THREAD_CHECKER(thread_checker_);
+
   base::WeakPtrFactory<D3D11VideoDecoderImpl> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(D3D11VideoDecoderImpl);
diff --git a/media/gpu/windows/d3d11_video_decoder_unittest.cc b/media/gpu/windows/d3d11_video_decoder_unittest.cc
index ccddfb8a..a66a26a02 100644
--- a/media/gpu/windows/d3d11_video_decoder_unittest.cc
+++ b/media/gpu/windows/d3d11_video_decoder_unittest.cc
@@ -36,19 +36,12 @@
             nullptr,
             base::RepeatingCallback<gpu::CommandBufferStub*()>()) {}
 
-  MOCK_METHOD6(
-      Initialize,
-      void(const VideoDecoderConfig& config,
-           bool low_delay,
-           CdmContext* cdm_context,
-           const InitCB& init_cb,
-           const OutputCB& output_cb,
-           const WaitingForDecryptionKeyCB& waiting_for_decryption_key_cb));
+  void Initialize(InitCB init_cb,
+                  ReturnPictureBufferCB return_picture_buffer_cb) override {
+    MockInitialize();
+  }
 
-  MOCK_METHOD2(Decode,
-               void(scoped_refptr<DecoderBuffer> buffer,
-                    const DecodeCB& decode_cb));
-  MOCK_METHOD1(Reset, void(const base::RepeatingClosure& closure));
+  MOCK_METHOD0(MockInitialize, void());
 };
 
 class D3D11VideoDecoderTest : public ::testing::Test {
@@ -79,7 +72,9 @@
     decoder_ = base::WrapUnique<VideoDecoder>(
         d3d11_decoder_raw_ = new D3D11VideoDecoder(
             gpu_task_runner_, nullptr /* MediaLog */, gpu_preferences_,
-            gpu_workarounds_, std::move(impl)));
+            gpu_workarounds_, std::move(impl),
+            base::BindRepeating(
+                []() -> gpu::CommandBufferStub* { return nullptr; })));
     d3d11_decoder_raw_->SetCreateDeviceCallbackForTesting(
         base::BindRepeating(&D3D11CreateDeviceMock::Create,
                             base::Unretained(&create_device_mock_)));
@@ -102,7 +97,7 @@
 
     if (expectation == kExpectSuccess) {
       EXPECT_CALL(*this, MockInitCB(_)).Times(0);
-      EXPECT_CALL(*impl_, Initialize(_, low_delay, cdm_context, _, _, _));
+      EXPECT_CALL(*impl_, MockInitialize());
     } else {
       EXPECT_CALL(*this, MockInitCB(false));
     }
@@ -164,7 +159,10 @@
   CreateDecoder();
   // Make sure that we're testing H264.
   ASSERT_EQ(supported_config_.profile(), H264PROFILE_MAIN);
-  InitializeDecoder(supported_config_, kExpectSuccess);
+  // We do not actually try to initialize the decoder, since we don't mock
+  // out enough of D3D for that to work.  Instead, we just check that
+  // IsPotentiallySupported is correct.
+  EXPECT_TRUE(d3d11_decoder_raw_->IsPotentiallySupported(supported_config_));
 }
 
 TEST_F(D3D11VideoDecoderTest, DoesNotSupportVP8) {
diff --git a/mojo/public/cpp/base/big_buffer.cc b/mojo/public/cpp/base/big_buffer.cc
index 5f18359d..d7223ef 100644
--- a/mojo/public/cpp/base/big_buffer.cc
+++ b/mojo/public/cpp/base/big_buffer.cc
@@ -101,6 +101,12 @@
                 static_cast<uint8_t*>(shared_memory_->buffer_mapping_.get()));
       return;
     }
+
+    // Shared memory allocation failed, so we're going to inline the data. If
+    // the data is large enough to be rejected by Mojo internals, we crash early
+    // to disambiguate this case from other intentional large-IPC crashes. See
+    // https://crbug.com/872237.
+    CHECK_LE(bytes.size(), 127u * 1024 * 1024);
   }
 
   // Either the data is small enough or shared memory allocation failed. Either
diff --git a/net/android/network_library.cc b/net/android/network_library.cc
index 6b8680f..bc6fe9ac 100644
--- a/net/android/network_library.cc
+++ b/net/android/network_library.cc
@@ -23,8 +23,8 @@
 namespace android {
 
 void VerifyX509CertChain(const std::vector<std::string>& cert_chain,
-                         const std::string& auth_type,
-                         const std::string& host,
+                         base::StringPiece auth_type,
+                         base::StringPiece host,
                          CertVerifyStatusAndroid* status,
                          bool* is_issued_by_known_root,
                          std::vector<std::string>* verified_chain) {
diff --git a/net/android/network_library.h b/net/android/network_library.h
index f47f46b5..59076d8 100644
--- a/net/android/network_library.h
+++ b/net/android/network_library.h
@@ -13,6 +13,7 @@
 #include <string>
 #include <vector>
 
+#include "base/strings/string_piece.h"
 #include "net/android/cert_verify_result_android.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/mime_util.h"
@@ -27,8 +28,8 @@
 // certificate listed first.
 // |auth_type| is as per the Java X509Certificate.checkServerTrusted method.
 void VerifyX509CertChain(const std::vector<std::string>& cert_chain,
-                         const std::string& auth_type,
-                         const std::string& host,
+                         base::StringPiece auth_type,
+                         base::StringPiece host,
                          CertVerifyStatusAndroid* status,
                          bool* is_issued_by_known_root,
                          std::vector<std::string>* verified_chain);
diff --git a/net/dns/host_resolver.cc b/net/dns/host_resolver.cc
index 3880c7c..77e55f3 100644
--- a/net/dns/host_resolver.cc
+++ b/net/dns/host_resolver.cc
@@ -220,7 +220,13 @@
 
 // static
 HostResolverSource HostResolver::FlagsToSource(HostResolverFlags flags) {
-  if (flags & HOST_RESOLVER_SYSTEM_ONLY)
+  // To counter the lack of CNAME support in the async host resolver, SYSTEM is
+  // forced when CANONNAME flags is present. This restriction can be removed
+  // once CNAME support is added to the async resolver.  See
+  // https://crbug.com/872665
+  //
+  // It is intentional that the presence of either flag forces SYSTEM.
+  if (flags & (HOST_RESOLVER_SYSTEM_ONLY | HOST_RESOLVER_CANONNAME))
     return HostResolverSource::SYSTEM;
 
   return HostResolverSource::ANY;
diff --git a/net/dns/mapped_host_resolver.cc b/net/dns/mapped_host_resolver.cc
index 8a237dda..3a6eeb6 100644
--- a/net/dns/mapped_host_resolver.cc
+++ b/net/dns/mapped_host_resolver.cc
@@ -114,6 +114,24 @@
   return impl_->GetNoIPv6OnWifi();
 }
 
+void MappedHostResolver::SetRequestContext(URLRequestContext* request_context) {
+  impl_->SetRequestContext(request_context);
+}
+
+void MappedHostResolver::AddDnsOverHttpsServer(std::string spec,
+                                               bool use_post) {
+  impl_->AddDnsOverHttpsServer(spec, use_post);
+}
+
+void MappedHostResolver::ClearDnsOverHttpsServers() {
+  impl_->ClearDnsOverHttpsServers();
+}
+
+const std::vector<DnsConfig::DnsOverHttpsServerConfig>*
+MappedHostResolver::GetDnsOverHttpsServersForTesting() const {
+  return impl_->GetDnsOverHttpsServersForTesting();
+}
+
 int MappedHostResolver::ApplyRules(RequestInfo* info) const {
   HostPortPair host_port(info->host_port_pair());
   if (rules_.RewriteHost(&host_port)) {
diff --git a/net/dns/mapped_host_resolver.h b/net/dns/mapped_host_resolver.h
index 88edc98..850a2af6 100644
--- a/net/dns/mapped_host_resolver.h
+++ b/net/dns/mapped_host_resolver.h
@@ -7,6 +7,7 @@
 
 #include <memory>
 #include <string>
+#include <vector>
 
 #include "net/base/completion_once_callback.h"
 #include "net/base/host_mapping_rules.h"
@@ -65,15 +66,18 @@
                             HostCache::EntryStaleness* stale_info,
                             const NetLogWithSource& source_net_log) override;
   void SetDnsClientEnabled(bool enabled) override;
-
   HostCache* GetHostCache() override;
   bool HasCached(base::StringPiece hostname,
                  HostCache::Entry::Source* source_out,
                  HostCache::EntryStaleness* stale_out) const override;
-
   std::unique_ptr<base::Value> GetDnsConfigAsValue() const override;
   void SetNoIPv6OnWifi(bool no_ipv6_on_wifi) override;
   bool GetNoIPv6OnWifi() override;
+  void SetRequestContext(URLRequestContext* request_context) override;
+  void AddDnsOverHttpsServer(std::string spec, bool use_post) override;
+  void ClearDnsOverHttpsServers() override;
+  const std::vector<DnsConfig::DnsOverHttpsServerConfig>*
+  GetDnsOverHttpsServersForTesting() const override;
 
  private:
   class AlwaysErrorRequestImpl;
diff --git a/net/extras/sqlite/sqlite_persistent_cookie_store.cc b/net/extras/sqlite/sqlite_persistent_cookie_store.cc
index 67a46fc..99f2e704 100644
--- a/net/extras/sqlite/sqlite_persistent_cookie_store.cc
+++ b/net/extras/sqlite/sqlite_persistent_cookie_store.cc
@@ -11,6 +11,8 @@
 
 #include "base/bind.h"
 #include "base/callback.h"
+#include "base/debug/alias.h"
+#include "base/debug/dump_without_crashing.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/location.h"
@@ -181,6 +183,7 @@
         initialized_(false),
         corruption_detected_(false),
         restore_old_session_cookies_(restore_old_session_cookies),
+        reported_giant_queue_(false),
         num_cookies_read_(0),
         client_task_runner_(client_task_runner),
         background_task_runner_(background_task_runner),
@@ -310,6 +313,9 @@
   // Batch a cookie operation (add or delete)
   void BatchOperation(PendingOperation::OperationType op,
                       const CanonicalCookie& cc);
+
+  void ReportGiantQueue(size_t size);
+
   // Commit our pending operations to the database.
   void Commit();
   // Close() executed on the background runner.
@@ -357,6 +363,10 @@
   // If false, we should filter out session cookies when reading the DB.
   bool restore_old_session_cookies_;
 
+  // If true, we already reported a failure due to seemingly wedged
+  // operations queue, so don't do it again.
+  bool reported_giant_queue_;
+
   // The cumulative time spent loading the cookies on the background runner.
   // Incremented and reported from the background runner.
   base::TimeDelta cookie_load_duration_;
@@ -1257,6 +1267,10 @@
   static const int kCommitIntervalMs = 30 * 1000;
   // Commit right away if we have more than 512 outstanding operations.
   static const size_t kCommitAfterBatchSize = 512;
+
+  // Threshold after which we report a problem.
+  static const size_t kReportGiantQueueSizeThreshold = 50 * 1024;
+
   DCHECK(!background_task_runner_->RunsTasksInCurrentSequence());
 
   // We do a full copy of the cookie here, and hopefully just here.
@@ -1279,9 +1293,19 @@
   } else if (num_pending == kCommitAfterBatchSize) {
     // We've reached a big enough batch, fire off a commit now.
     PostBackgroundTask(FROM_HERE, base::Bind(&Backend::Commit, this));
+  } else if (num_pending >= kReportGiantQueueSizeThreshold &&
+             !reported_giant_queue_) {
+    ReportGiantQueue(num_pending);
+    reported_giant_queue_ = true;
   }
 }
 
+void SQLitePersistentCookieStore::Backend::ReportGiantQueue(
+    size_t num_pending) {
+  base::debug::Alias(&num_pending);
+  base::debug::DumpWithoutCrashing();
+}
+
 void SQLitePersistentCookieStore::Backend::Commit() {
   DCHECK(background_task_runner_->RunsTasksInCurrentSequence());
 
diff --git a/net/http/http_auth_handler_negotiate_unittest.cc b/net/http/http_auth_handler_negotiate_unittest.cc
index db8c9a6..fc5a7af 100644
--- a/net/http/http_auth_handler_negotiate_unittest.cc
+++ b/net/http/http_auth_handler_negotiate_unittest.cc
@@ -9,6 +9,7 @@
 #include "base/memory/ptr_util.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "build/build_config.h"
 #include "net/base/net_errors.h"
 #include "net/base/test_completion_callback.h"
 #include "net/dns/mock_host_resolver.h"
@@ -49,8 +50,8 @@
   void SetUp() override {
     auth_library_ = new MockAuthLibrary();
     resolver_.reset(new MockHostResolver());
-    resolver_->rules()->AddIPLiteralRule("alias", "10.0.0.2",
-                                           "canonical.example.com");
+    resolver_->rules_map()[HostResolverSource::SYSTEM]->AddIPLiteralRule(
+        "alias", "10.0.0.2", "canonical.example.com");
 
     http_auth_preferences_.reset(new MockAllowHttpAuthPreferences());
     factory_.reset(new HttpAuthHandlerNegotiate::Factory());
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc
index 9c0395e..a993688 100644
--- a/net/http/http_network_session.cc
+++ b/net/http/http_network_session.cc
@@ -244,6 +244,7 @@
                          params.support_ietf_format_quic_altsvc,
                          params.spdy_session_max_recv_window_size,
                          AddDefaultHttp2Settings(params.http2_settings),
+                         params.greased_http2_frame,
                          params.time_func),
       http_stream_factory_(std::make_unique<HttpStreamFactory>(this)),
       params_(params),
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h
index 16aebbd..8048238d 100644
--- a/net/http/http_network_session.h
+++ b/net/http/http_network_session.h
@@ -21,6 +21,7 @@
 #include "base/memory/memory_pressure_monitor.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "base/threading/thread_checker.h"
 #include "net/base/host_mapping_rules.h"
 #include "net/base/host_port_pair.h"
@@ -113,7 +114,18 @@
     size_t spdy_session_max_recv_window_size;
     // HTTP/2 connection settings.
     // Unknown settings will still be sent to the server.
+    // Might contain unknown setting identifiers from a predefined set that
+    // servers are supposed to ignore, see
+    // https://tools.ietf.org/html/draft-bishop-httpbis-grease-00.
+    // The same setting will be sent on every connection to prevent the retry
+    // logic from hiding broken servers.
     spdy::SettingsMap http2_settings;
+    // If set, an HTTP/2 frame with a reserved frame type will be sent after
+    // every HEADERS and SETTINGS frame.  See
+    // https://tools.ietf.org/html/draft-bishop-httpbis-grease-00.
+    // The same frame will be sent out on all connections to prevent the retry
+    // logic from hiding broken servers.
+    base::Optional<SpdySessionPool::GreasedHttp2Frame> greased_http2_frame;
     // Source of time for SPDY connections.
     SpdySessionPool::TimeFunc time_func;
     // Whether to enable HTTP/2 Alt-Svc entries.
diff --git a/net/spdy/spdy_session.cc b/net/spdy/spdy_session.cc
index 85847670..50de3d4 100644
--- a/net/spdy/spdy_session.cc
+++ b/net/spdy/spdy_session.cc
@@ -152,6 +152,42 @@
   return kVaryHasNoAcceptEncoding;
 }
 
+// A SpdyBufferProducer implementation that creates an HTTP/2 frame by adding
+// stream ID to greased frame parameters.
+class GreasedBufferProducer : public SpdyBufferProducer {
+ public:
+  GreasedBufferProducer() = delete;
+  GreasedBufferProducer(
+      base::WeakPtr<SpdyStream> stream,
+      const SpdySessionPool::GreasedHttp2Frame* greased_http2_frame,
+      BufferedSpdyFramer* buffered_spdy_framer)
+      : stream_(stream),
+        greased_http2_frame_(greased_http2_frame),
+        buffered_spdy_framer_(buffered_spdy_framer) {}
+
+  ~GreasedBufferProducer() override = default;
+
+  std::unique_ptr<SpdyBuffer> ProduceBuffer() override {
+    const spdy::SpdyStreamId stream_id = stream_ ? stream_->stream_id() : 0;
+    spdy::SpdyUnknownIR frame(stream_id, greased_http2_frame_->type,
+                              greased_http2_frame_->flags,
+                              greased_http2_frame_->payload);
+    auto serialized_frame = std::make_unique<spdy::SpdySerializedFrame>(
+        buffered_spdy_framer_->SerializeFrame(frame));
+    return std::make_unique<SpdyBuffer>(std::move(serialized_frame));
+  }
+
+  size_t EstimateMemoryUsage() const override {
+    return base::trace_event::EstimateMemoryUsage(
+        greased_http2_frame_->payload);
+  }
+
+ private:
+  base::WeakPtr<SpdyStream> stream_;
+  const SpdySessionPool::GreasedHttp2Frame* const greased_http2_frame_;
+  BufferedSpdyFramer* buffered_spdy_framer_;
+};
+
 bool IsSpdySettingAtDefaultInitialValue(spdy::SpdySettingsId setting_id,
                                         uint32_t value) {
   switch (setting_id) {
@@ -784,6 +820,8 @@
     bool is_trusted_proxy,
     size_t session_max_recv_window_size,
     const spdy::SettingsMap& initial_settings,
+    const base::Optional<SpdySessionPool::GreasedHttp2Frame>&
+        greased_http2_frame,
     TimeFunc time_func,
     ServerPushDelegate* push_delegate,
     NetLog* net_log)
@@ -807,6 +845,7 @@
       write_state_(WRITE_STATE_IDLE),
       error_on_close_(OK),
       initial_settings_(initial_settings),
+      greased_http2_frame_(greased_http2_frame),
       max_concurrent_streams_(kInitialMaxConcurrentStreams),
       max_concurrent_pushed_streams_(
           initial_settings.at(spdy::SETTINGS_MAX_CONCURRENT_STREAMS)),
@@ -854,6 +893,12 @@
   DCHECK(
       base::ContainsKey(initial_settings_, spdy::SETTINGS_INITIAL_WINDOW_SIZE));
 
+  if (greased_http2_frame_) {
+    // See https://tools.ietf.org/html/draft-bishop-httpbis-grease-00
+    // for reserved frame types.
+    DCHECK_EQ(0x0b, greased_http2_frame_.value().type % 0x1f);
+  }
+
   // TODO(mbelshe): consider randomization of the stream_hi_water_mark.
 }
 
@@ -2558,6 +2603,15 @@
 
   write_queue_.Enqueue(priority, frame_type, std::move(producer), stream,
                        traffic_annotation);
+  if (greased_http2_frame_ && (frame_type == spdy::SpdyFrameType::SETTINGS ||
+                               frame_type == spdy::SpdyFrameType::HEADERS)) {
+    write_queue_.Enqueue(
+        priority,
+        static_cast<spdy::SpdyFrameType>(greased_http2_frame_.value().type),
+        std::make_unique<GreasedBufferProducer>(
+            stream, &greased_http2_frame_.value(), buffered_spdy_framer_.get()),
+        stream, traffic_annotation);
+  }
   MaybePostWriteLoop();
 }
 
diff --git a/net/spdy/spdy_session.h b/net/spdy/spdy_session.h
index 88ee4d7b..b4bae19 100644
--- a/net/spdy/spdy_session.h
+++ b/net/spdy/spdy_session.h
@@ -20,6 +20,7 @@
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "base/strings/string_piece.h"
 #include "base/time/time.h"
 #include "net/base/completion_once_callback.h"
@@ -303,6 +304,8 @@
               bool is_trusted_proxy,
               size_t session_max_recv_window_size,
               const spdy::SettingsMap& initial_settings,
+              const base::Optional<SpdySessionPool::GreasedHttp2Frame>&
+                  greased_http2_frame,
               TimeFunc time_func,
               ServerPushDelegate* push_delegate,
               NetLog* net_log);
@@ -1030,6 +1033,11 @@
   // and maximum HPACK dynamic table size.
   const spdy::SettingsMap initial_settings_;
 
+  // If set, an HTTP/2 frame with a reserved frame type will be sent after every
+  // valid HTTP/2 frame.  See
+  // https://tools.ietf.org/html/draft-bishop-httpbis-grease-00.
+  const base::Optional<SpdySessionPool::GreasedHttp2Frame> greased_http2_frame_;
+
   // Limits
   size_t max_concurrent_streams_;
   size_t max_concurrent_pushed_streams_;
diff --git a/net/spdy/spdy_session_pool.cc b/net/spdy/spdy_session_pool.cc
index ee368e0..670a0aa2 100644
--- a/net/spdy/spdy_session_pool.cc
+++ b/net/spdy/spdy_session_pool.cc
@@ -56,6 +56,7 @@
     bool support_ietf_format_quic_altsvc,
     size_t session_max_recv_window_size,
     const spdy::SettingsMap& initial_settings,
+    const base::Optional<GreasedHttp2Frame>& greased_http2_frame,
     SpdySessionPool::TimeFunc time_func)
     : http_server_properties_(http_server_properties),
       transport_security_state_(transport_security_state),
@@ -68,6 +69,7 @@
       support_ietf_format_quic_altsvc_(support_ietf_format_quic_altsvc),
       session_max_recv_window_size_(session_max_recv_window_size),
       initial_settings_(initial_settings),
+      greased_http2_frame_(greased_http2_frame),
       time_func_(time_func),
       push_delegate_(nullptr) {
   NetworkChangeNotifier::AddIPAddressObserver(this);
@@ -110,8 +112,8 @@
       ssl_config_service_, quic_supported_versions_,
       enable_sending_initial_data_, enable_ping_based_connection_checking_,
       support_ietf_format_quic_altsvc_, is_trusted_proxy,
-      session_max_recv_window_size_, initial_settings_, time_func_,
-      push_delegate_, net_log.net_log());
+      session_max_recv_window_size_, initial_settings_, greased_http2_frame_,
+      time_func_, push_delegate_, net_log.net_log());
 
   new_session->InitializeWithSocket(std::move(connection), this);
 
diff --git a/net/spdy/spdy_session_pool.h b/net/spdy/spdy_session_pool.h
index 9fe3e1c..7376bee5 100644
--- a/net/spdy/spdy_session_pool.h
+++ b/net/spdy/spdy_session_pool.h
@@ -17,6 +17,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
+#include "base/optional.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/ip_endpoint.h"
 #include "net/base/net_errors.h"
@@ -56,6 +57,16 @@
  public:
   typedef base::TimeTicks (*TimeFunc)(void);
 
+  // Struct to hold randomly generated frame parameters to be used for sending
+  // frames on the wire to "grease" frame type.  Frame type has to be one of
+  // the reserved values defined in
+  // https://tools.ietf.org/html/draft-bishop-httpbis-grease-00.
+  struct GreasedHttp2Frame {
+    uint8_t type;
+    uint8_t flags;
+    std::string payload;
+  };
+
   SpdySessionPool(
       HostResolver* host_resolver,
       SSLConfigService* ssl_config_service,
@@ -66,6 +77,7 @@
       bool support_ietf_format_quic_altsvc,
       size_t session_max_recv_window_size,
       const spdy::SettingsMap& initial_settings,
+      const base::Optional<GreasedHttp2Frame>& greased_http2_frame,
       SpdySessionPool::TimeFunc time_func);
   ~SpdySessionPool() override;
 
@@ -276,6 +288,11 @@
   // and maximum HPACK dynamic table size.
   const spdy::SettingsMap initial_settings_;
 
+  // If set, an HTTP/2 frame with a reserved frame type will be sent after every
+  // valid HTTP/2 frame.  See
+  // https://tools.ietf.org/html/draft-bishop-httpbis-grease-00.
+  const base::Optional<GreasedHttp2Frame> greased_http2_frame_;
+
   // TODO(xunjieli): Merge these two.
   SpdySessionRequestMap spdy_session_request_map_;
   typedef std::map<SpdySessionKey, std::list<base::Closure>>
diff --git a/net/spdy/spdy_session_unittest.cc b/net/spdy/spdy_session_unittest.cc
index 6e1e03c..19d899b 100644
--- a/net/spdy/spdy_session_unittest.cc
+++ b/net/spdy/spdy_session_unittest.cc
@@ -12,9 +12,11 @@
 #include "base/bind.h"
 #include "base/callback.h"
 #include "base/run_loop.h"
+#include "base/stl_util.h"
 #include "base/test/metrics/histogram_tester.h"
 #include "base/test/scoped_feature_list.h"
 #include "base/test/scoped_task_environment.h"
+#include "net/base/hex_utils.h"
 #include "net/base/host_port_pair.h"
 #include "net/base/io_buffer.h"
 #include "net/base/ip_endpoint.h"
@@ -5890,6 +5892,96 @@
   EXPECT_FALSE(session_);
 }
 
+TEST_F(SpdySessionTest, GreaseFrameType) {
+  const uint8_t type = 0x0b;
+  const uint8_t flags = 0xcc;
+  const std::string payload("foo");
+  session_deps_.greased_http2_frame =
+      base::Optional<net::SpdySessionPool::GreasedHttp2Frame>(
+          {type, flags, payload});
+
+  // Connection preface.
+  spdy::SpdySerializedFrame preface(
+      const_cast<char*>(spdy::kHttp2ConnectionHeaderPrefix),
+      spdy::kHttp2ConnectionHeaderPrefixSize,
+      /* owns_buffer = */ false);
+
+  // Initial SETTINGS frame.
+  spdy::SettingsMap expected_settings;
+  expected_settings[spdy::SETTINGS_HEADER_TABLE_SIZE] = kSpdyMaxHeaderTableSize;
+  expected_settings[spdy::SETTINGS_MAX_CONCURRENT_STREAMS] =
+      kSpdyMaxConcurrentPushedStreams;
+  spdy::SpdySerializedFrame settings_frame(
+      spdy_util_.ConstructSpdySettings(expected_settings));
+
+  spdy::SpdySerializedFrame combined_frame =
+      CombineFrames({&preface, &settings_frame});
+
+  // Greased frame sent on stream 0 after initial SETTINGS frame.
+  const char kRawFrameData0[] = {
+      0x00, 0x00, 0x03,        // length
+      0x0b,                    // type
+      0xcc,                    // flags
+      0x00, 0x00, 0x00, 0x00,  // stream ID
+      'f',  'o',  'o'          // payload
+  };
+  spdy::SpdySerializedFrame grease0(const_cast<char*>(kRawFrameData0),
+                                    base::size(kRawFrameData0),
+                                    /* owns_buffer = */ false);
+  spdy::SpdySerializedFrame req(
+      spdy_util_.ConstructSpdyGet(nullptr, 0, 1, DEFAULT_PRIORITY));
+
+  // Greased frame sent on stream 1 after request.
+  const char kRawFrameData1[] = {
+      0x00, 0x00, 0x03,        // length
+      0x0b,                    // type
+      0xcc,                    // flags
+      0x00, 0x00, 0x00, 0x01,  // stream ID
+      'f',  'o',  'o'          // payload
+  };
+  spdy::SpdySerializedFrame grease1(const_cast<char*>(kRawFrameData1),
+                                    base::size(kRawFrameData1),
+                                    /* owns_buffer = */ false);
+
+  MockWrite writes[] = {CreateMockWrite(combined_frame, 0),
+                        CreateMockWrite(grease0, 1), CreateMockWrite(req, 2),
+                        CreateMockWrite(grease1, 3)};
+
+  spdy::SpdySerializedFrame resp(
+      spdy_util_.ConstructSpdyGetReply(nullptr, 0, 1));
+  spdy::SpdySerializedFrame body(spdy_util_.ConstructSpdyDataFrame(1, true));
+
+  MockRead reads[] = {CreateMockRead(resp, 4), CreateMockRead(body, 5),
+                      MockRead(ASYNC, 0, 6)};
+
+  SequencedSocketData data(reads, writes);
+  session_deps_.socket_factory->AddSocketDataProvider(&data);
+  AddSSLSocketData();
+
+  CreateNetworkSession();
+
+  SpdySessionPoolPeer pool_peer(spdy_session_pool_);
+  pool_peer.SetEnableSendingInitialData(true);
+
+  CreateSpdySession();
+
+  base::WeakPtr<SpdyStream> stream = CreateStreamSynchronously(
+      SPDY_REQUEST_RESPONSE_STREAM, session_, test_url_, DEFAULT_PRIORITY,
+      NetLogWithSource());
+  test::StreamDelegateDoNothing delegate(stream);
+  stream->SetDelegate(&delegate);
+
+  stream->SendRequestHeaders(spdy_util_.ConstructGetHeaderBlock(kDefaultUrl),
+                             NO_MORE_DATA_TO_SEND);
+
+  EXPECT_THAT(delegate.WaitForClose(), IsOk());
+
+  base::RunLoop().RunUntilIdle();
+
+  EXPECT_TRUE(data.AllWriteDataConsumed());
+  EXPECT_TRUE(data.AllReadDataConsumed());
+}
+
 enum ReadIfReadySupport {
   // ReadIfReady() field trial is enabled, and ReadIfReady() is implemented.
   READ_IF_READY_ENABLED_SUPPORTED,
diff --git a/net/spdy/spdy_stream.cc b/net/spdy/spdy_stream.cc
index 38531de..edfada1e 100644
--- a/net/spdy/spdy_stream.cc
+++ b/net/spdy/spdy_stream.cc
@@ -586,6 +586,12 @@
     return;
   }
 
+  // Frame types reserved in
+  // https://tools.ietf.org/html/draft-bishop-httpbis-grease-00 ought to be
+  // ignored.
+  if (static_cast<uint8_t>(frame_type) % 0x1f == 0x0b)
+    return;
+
   DCHECK_NE(type_, SPDY_PUSH_STREAM);
   CHECK(frame_type == spdy::SpdyFrameType::HEADERS ||
         frame_type == spdy::SpdyFrameType::DATA)
diff --git a/net/spdy/spdy_test_util_common.cc b/net/spdy/spdy_test_util_common.cc
index 5e408256..e285614 100644
--- a/net/spdy/spdy_test_util_common.cc
+++ b/net/spdy/spdy_test_util_common.cc
@@ -28,7 +28,6 @@
 #include "net/socket/transport_client_socket_pool.h"
 #include "net/spdy/buffered_spdy_framer.h"
 #include "net/spdy/spdy_http_utils.h"
-#include "net/spdy/spdy_session_pool.h"
 #include "net/spdy/spdy_stream.h"
 #include "net/test/gtest_util.h"
 #include "net/third_party/spdy/core/spdy_alt_svc_wire_format.h"
@@ -385,6 +384,7 @@
       session_deps->enable_http2_alternative_service;
   params.enable_websocket_over_http2 =
       session_deps->enable_websocket_over_http2;
+  params.greased_http2_frame = session_deps->greased_http2_frame;
   params.http_09_on_non_default_ports_enabled =
       session_deps->http_09_on_non_default_ports_enabled;
   params.disable_idle_sockets_close_on_memory_pressure =
diff --git a/net/spdy/spdy_test_util_common.h b/net/spdy/spdy_test_util_common.h
index 08312e8..bedaf7c 100644
--- a/net/spdy/spdy_test_util_common.h
+++ b/net/spdy/spdy_test_util_common.h
@@ -33,6 +33,7 @@
 #include "net/proxy_resolution/proxy_resolution_service.h"
 #include "net/socket/socket_test_util.h"
 #include "net/spdy/spdy_session.h"
+#include "net/spdy/spdy_session_pool.h"
 #include "net/ssl/ssl_config_service_defaults.h"
 #include "net/third_party/spdy/core/spdy_protocol.h"
 #include "net/url_request/url_request_context.h"
@@ -49,7 +50,6 @@
 class HostPortPair;
 class NetLogWithSource;
 class SpdySessionKey;
-class SpdySessionPool;
 class SpdyStream;
 class SpdyStreamRequest;
 class TransportSecurityState;
@@ -215,6 +215,7 @@
   std::unique_ptr<ProxyDelegate> proxy_delegate;
   bool enable_http2_alternative_service;
   bool enable_websocket_over_http2;
+  base::Optional<SpdySessionPool::GreasedHttp2Frame> greased_http2_frame;
   NetLog* net_log;
   bool http_09_on_non_default_ports_enabled;
   bool disable_idle_sockets_close_on_memory_pressure;
diff --git a/services/network/cors/cors_url_loader.cc b/services/network/cors/cors_url_loader.cc
index 0bd18b7..8d95257d 100644
--- a/services/network/cors/cors_url_loader.cc
+++ b/services/network/cors/cors_url_loader.cc
@@ -27,7 +27,7 @@
 }
 
 bool NeedsPreflight(const ResourceRequest& request) {
-  if (!cors::IsCORSEnabledRequestMode(request.fetch_request_mode))
+  if (!IsCORSEnabledRequestMode(request.fetch_request_mode))
     return false;
 
   if (request.is_external_request)
@@ -46,13 +46,9 @@
   if (!IsCORSSafelistedMethod(request.method))
     return true;
 
-  for (const auto& header : request.headers.GetHeaderVector()) {
-    if (!IsCORSSafelistedHeader(header.key, header.value) &&
-        !IsForbiddenHeader(header.key)) {
-      return true;
-    }
-  }
-  return false;
+  return !CORSUnsafeNotForbiddenRequestHeaderNames(
+              request.headers.GetHeaderVector())
+              .empty();
 }
 
 }  // namespace
@@ -92,7 +88,7 @@
 
 void CORSURLLoader::Start() {
   if (fetch_cors_flag_ &&
-      cors::IsCORSEnabledRequestMode(request_.fetch_request_mode)) {
+      IsCORSEnabledRequestMode(request_.fetch_request_mode)) {
     // Username and password should be stripped in a CORS-enabled request.
     if (request_.url.has_username() || request_.url.has_password()) {
       GURL::Replacements replacements;
diff --git a/services/network/cors/preflight_controller.cc b/services/network/cors/preflight_controller.cc
index 629fd22..8828fa4 100644
--- a/services/network/cors/preflight_controller.cc
+++ b/services/network/cors/preflight_controller.cc
@@ -41,18 +41,11 @@
 //  - byte-lowercased
 std::string CreateAccessControlRequestHeadersHeader(
     const net::HttpRequestHeaders& headers) {
-  std::vector<std::string> filtered_headers;
-  for (const auto& header : headers.GetHeaderVector()) {
-    // Exclude CORS-safelisted headers.
-    if (cors::IsCORSSafelistedHeader(header.key, header.value))
-      continue;
-    // Exclude the forbidden headers because they may be added by the user
-    // agent. They must be checked separately and rejected for
-    // JavaScript-initiated requests.
-    if (cors::IsForbiddenHeader(header.key))
-      continue;
-    filtered_headers.push_back(base::ToLowerASCII(header.key));
-  }
+  // Exclude the forbidden headers because they may be added by the user
+  // agent. They must be checked separately and rejected for
+  // JavaScript-initiated requests.
+  std::vector<std::string> filtered_headers =
+      CORSUnsafeNotForbiddenRequestHeaderNames(headers.GetHeaderVector());
   if (filtered_headers.empty())
     return std::string();
 
@@ -88,18 +81,18 @@
   preflight_request->load_flags |= net::LOAD_DO_NOT_SEND_AUTH_DATA;
 
   preflight_request->headers.SetHeader(
-      cors::header_names::kAccessControlRequestMethod, request.method);
+      header_names::kAccessControlRequestMethod, request.method);
 
   std::string request_headers =
       CreateAccessControlRequestHeadersHeader(request.headers);
   if (!request_headers.empty()) {
     preflight_request->headers.SetHeader(
-        cors::header_names::kAccessControlRequestHeaders, request_headers);
+        header_names::kAccessControlRequestHeaders, request_headers);
   }
 
   if (request.is_external_request) {
     preflight_request->headers.SetHeader(
-        cors::header_names::kAccessControlRequestExternal, "true");
+        header_names::kAccessControlRequestExternal, "true");
   }
 
   DCHECK(request.request_initiator);
@@ -130,10 +123,9 @@
   // TODO(toyoshim): Reflect --allow-file-access-from-files flag.
   *detected_error_status = CheckPreflightAccess(
       final_url, head.headers->response_code(),
+      GetHeaderString(head.headers, header_names::kAccessControlAllowOrigin),
       GetHeaderString(head.headers,
-                      cors::header_names::kAccessControlAllowOrigin),
-      GetHeaderString(head.headers,
-                      cors::header_names::kAccessControlAllowCredentials),
+                      header_names::kAccessControlAllowCredentials),
       original_request.fetch_credentials_mode,
       tainted ? url::Origin() : *original_request.request_initiator,
       false /* allow_file_origin */);
diff --git a/services/network/cors/preflight_controller_unittest.cc b/services/network/cors/preflight_controller_unittest.cc
index a5cb266..e2f2e85 100644
--- a/services/network/cors/preflight_controller_unittest.cc
+++ b/services/network/cors/preflight_controller_unittest.cc
@@ -50,7 +50,7 @@
   EXPECT_EQ("null", header);
 
   EXPECT_TRUE(preflight->headers.GetHeader(
-      cors::header_names::kAccessControlRequestHeaders, &header));
+      header_names::kAccessControlRequestHeaders, &header));
   EXPECT_EQ("apple,content-type,kiwifruit,orange,strawberry", header);
 }
 
@@ -73,7 +73,7 @@
   // left out in the preflight request.
   std::string header;
   EXPECT_FALSE(preflight->headers.GetHeader(
-      cors::header_names::kAccessControlRequestHeaders, &header));
+      header_names::kAccessControlRequestHeaders, &header));
 }
 
 TEST(PreflightControllerCreatePreflightRequestTest, Credentials) {
@@ -108,7 +108,7 @@
   // Empty list also; see comment in test above.
   std::string header;
   EXPECT_FALSE(preflight->headers.GetHeader(
-      cors::header_names::kAccessControlRequestHeaders, &header));
+      header_names::kAccessControlRequestHeaders, &header));
 }
 
 TEST(PreflightControllerCreatePreflightRequestTest, IncludeNonSimpleHeader) {
@@ -123,7 +123,7 @@
 
   std::string header;
   EXPECT_TRUE(preflight->headers.GetHeader(
-      cors::header_names::kAccessControlRequestHeaders, &header));
+      header_names::kAccessControlRequestHeaders, &header));
   EXPECT_EQ("x-custom-header", header);
 }
 
@@ -141,7 +141,7 @@
 
   std::string header;
   EXPECT_TRUE(preflight->headers.GetHeader(
-      cors::header_names::kAccessControlRequestHeaders, &header));
+      header_names::kAccessControlRequestHeaders, &header));
   EXPECT_EQ("content-type", header);
 }
 
@@ -157,7 +157,7 @@
 
   std::string header;
   EXPECT_FALSE(preflight->headers.GetHeader(
-      cors::header_names::kAccessControlRequestHeaders, &header));
+      header_names::kAccessControlRequestHeaders, &header));
 }
 
 TEST(PreflightControllerCreatePreflightRequestTest, Tainted) {
@@ -256,7 +256,7 @@
           net::test_server::ShouldHandle(request, "/tainted")
               ? url::Origin()
               : url::Origin::Create(test_server_.base_url());
-      response->AddCustomHeader(cors::header_names::kAccessControlAllowOrigin,
+      response->AddCustomHeader(header_names::kAccessControlAllowOrigin,
                                 origin.Serialize());
       response->AddCustomHeader(header_names::kAccessControlAllowMethods,
                                 "GET, OPTIONS");
diff --git a/services/network/p2p/socket_manager.cc b/services/network/p2p/socket_manager.cc
index 9c16446..27d85b6 100644
--- a/services/network/p2p/socket_manager.cc
+++ b/services/network/p2p/socket_manager.cc
@@ -89,12 +89,14 @@
     if (host_name_.back() != '.')
       host_name_ += '.';
 
-    net::HostResolver::RequestInfo info(net::HostPortPair(host_name_, 0));
-    int result =
-        resolver_->Resolve(info, net::DEFAULT_PRIORITY, &addresses_,
-                           base::BindOnce(&P2PSocketManager::DnsRequest::OnDone,
-                                          base::Unretained(this)),
-                           &request_, net::NetLogWithSource());
+    net::HostPortPair host(host_name_, 0);
+    // TODO(crbug.com/879746): Pass in a
+    // net::HostResolver::ResolveHostParameters with source set to MDNS if we
+    // have a ".local." TLD (once MDNS is supported).
+    request_ =
+        resolver_->CreateRequest(host, net::NetLogWithSource(), base::nullopt);
+    int result = request_->Start(base::BindOnce(
+        &P2PSocketManager::DnsRequest::OnDone, base::Unretained(this)));
     if (result != net::ERR_IO_PENDING)
       OnDone(result);
   }
@@ -102,26 +104,24 @@
  private:
   void OnDone(int result) {
     net::IPAddressList list;
-    if (result != net::OK) {
+    const base::Optional<net::AddressList>& addresses =
+        request_->GetAddressResults();
+    if (result != net::OK || !addresses) {
       LOG(ERROR) << "Failed to resolve address for " << host_name_
                  << ", errorcode: " << result;
       done_callback_.Run(list);
       return;
     }
 
-    DCHECK(!addresses_.empty());
-    for (net::AddressList::iterator iter = addresses_.begin();
-         iter != addresses_.end(); ++iter) {
-      list.push_back(iter->address());
+    for (const auto& endpoint : *addresses) {
+      list.push_back(endpoint.address());
     }
     done_callback_.Run(list);
   }
 
-  net::AddressList addresses_;
-
   std::string host_name_;
   net::HostResolver* resolver_;
-  std::unique_ptr<net::HostResolver::Request> request_;
+  std::unique_ptr<net::HostResolver::ResolveHostRequest> request_;
 
   DoneCallback done_callback_;
 };
diff --git a/services/network/public/cpp/cors/cors.cc b/services/network/public/cpp/cors/cors.cc
index 0076d1b..b117c22 100644
--- a/services/network/public/cpp/cors/cors.cc
+++ b/services/network/public/cpp/cors/cors.cc
@@ -354,6 +354,10 @@
 }
 
 bool IsCORSSafelistedHeader(const std::string& name, const std::string& value) {
+  // If |value|’s length is greater than 128, then return false.
+  if (value.size() > 128)
+    return false;
+
   // https://fetch.spec.whatwg.org/#cors-safelisted-request-header
   // "A CORS-safelisted header is a header whose name is either one of `Accept`,
   // `Accept-Language`, and `Content-Language`, or whose name is
@@ -395,12 +399,89 @@
   if (lower_name == "save-data")
     return lower_value == "on";
 
+  if (lower_name == "accept") {
+    return (value.end() == std::find_if(value.begin(), value.end(), [](char c) {
+              return (c < 0x20 && c != 0x09) || c == 0x22 || c == 0x28 ||
+                     c == 0x29 || c == 0x3a || c == 0x3c || c == 0x3e ||
+                     c == 0x3f || c == 0x40 || c == 0x5b || c == 0x5c ||
+                     c == 0x5d || c == 0x7b || c == 0x7d || c >= 0x7f;
+            }));
+  }
+
+  if (lower_name == "accept-language" || lower_name == "content-language") {
+    return (value.end() == std::find_if(value.begin(), value.end(), [](char c) {
+              return !isalnum(c) && c != 0x20 && c != 0x2a && c != 0x2c &&
+                     c != 0x2d && c != 0x2e && c != 0x3b && c != 0x3d;
+            }));
+  }
+
   if (lower_name == "content-type")
     return IsCORSSafelistedLowerCaseContentType(lower_value);
 
   return true;
 }
 
+bool IsNoCORSSafelistedHeader(const std::string& name,
+                              const std::string& value) {
+  const std::string lower_name = base::ToLowerASCII(name);
+
+  if (lower_name != "accept" && lower_name != "accept-language" &&
+      lower_name != "content-language" && lower_name != "content-type") {
+    return false;
+  }
+
+  return IsCORSSafelistedHeader(lower_name, value);
+}
+
+std::vector<std::string> CORSUnsafeRequestHeaderNames(
+    const net::HttpRequestHeaders::HeaderVector& headers) {
+  std::vector<std::string> potentially_unsafe_names;
+  std::vector<std::string> header_names;
+
+  constexpr size_t kSafeListValueSizeMax = 1024;
+  size_t safe_list_value_size = 0;
+
+  for (const auto& header : headers) {
+    if (!IsCORSSafelistedHeader(header.key, header.value)) {
+      header_names.push_back(base::ToLowerASCII(header.key));
+    } else {
+      potentially_unsafe_names.push_back(base::ToLowerASCII(header.key));
+      safe_list_value_size += header.value.size();
+    }
+  }
+  if (safe_list_value_size > kSafeListValueSizeMax) {
+    header_names.insert(header_names.end(), potentially_unsafe_names.begin(),
+                        potentially_unsafe_names.end());
+  }
+  return header_names;
+}
+
+std::vector<std::string> CORSUnsafeNotForbiddenRequestHeaderNames(
+    const net::HttpRequestHeaders::HeaderVector& headers) {
+  std::vector<std::string> header_names;
+  std::vector<std::string> potentially_unsafe_names;
+
+  constexpr size_t kSafeListValueSizeMax = 1024;
+  size_t safe_list_value_size = 0;
+
+  for (const auto& header : headers) {
+    if (IsForbiddenHeader(header.key))
+      continue;
+
+    if (!IsCORSSafelistedHeader(header.key, header.value)) {
+      header_names.push_back(base::ToLowerASCII(header.key));
+    } else {
+      potentially_unsafe_names.push_back(base::ToLowerASCII(header.key));
+      safe_list_value_size += header.value.size();
+    }
+  }
+  if (safe_list_value_size > kSafeListValueSizeMax) {
+    header_names.insert(header_names.end(), potentially_unsafe_names.begin(),
+                        potentially_unsafe_names.end());
+  }
+  return header_names;
+}
+
 bool IsForbiddenMethod(const std::string& method) {
   static const std::vector<std::string> forbidden_methods = {"trace", "track",
                                                              "connect"};
diff --git a/services/network/public/cpp/cors/cors.h b/services/network/public/cpp/cors/cors.h
index ec91457..cbe6219 100644
--- a/services/network/public/cpp/cors/cors.h
+++ b/services/network/public/cpp/cors/cors.h
@@ -6,9 +6,11 @@
 #define SERVICES_NETWORK_PUBLIC_CPP_CORS_CORS_H_
 
 #include <string>
+#include <vector>
 
 #include "base/component_export.h"
 #include "base/optional.h"
+#include "net/http/http_request_headers.h"
 #include "services/network/public/cpp/cors/cors_error_status.h"
 #include "services/network/public/mojom/cors.mojom-shared.h"
 #include "services/network/public/mojom/fetch_api.mojom-shared.h"
@@ -117,6 +119,26 @@
 bool IsCORSSafelistedContentType(const std::string& name);
 COMPONENT_EXPORT(NETWORK_CPP)
 bool IsCORSSafelistedHeader(const std::string& name, const std::string& value);
+COMPONENT_EXPORT(NETWORK_CPP)
+bool IsNoCORSSafelistedHeader(const std::string& name,
+                              const std::string& value);
+
+// https://fetch.spec.whatwg.org/#cors-unsafe-request-header-names
+// |headers| must not contain multiple headers for the same name.
+// The returned list is NOT sorted.
+// The returned list consists of lower-cased names.
+COMPONENT_EXPORT(NETWORK_CPP)
+std::vector<std::string> CORSUnsafeRequestHeaderNames(
+    const net::HttpRequestHeaders::HeaderVector& headers);
+
+// https://fetch.spec.whatwg.org/#cors-unsafe-request-header-names
+// Returns header names which are not CORS-safelisted AND not forbidden.
+// |headers| must not contain multiple headers for the same name.
+// The returned list is NOT sorted.
+// The returned list consists of lower-cased names.
+COMPONENT_EXPORT(NETWORK_CPP)
+std::vector<std::string> CORSUnsafeNotForbiddenRequestHeaderNames(
+    const net::HttpRequestHeaders::HeaderVector& headers);
 
 // Checks forbidden method in the fetch spec.
 // See https://fetch.spec.whatwg.org/#forbidden-method.
diff --git a/services/network/public/cpp/cors/cors_unittest.cc b/services/network/public/cpp/cors/cors_unittest.cc
index 695b04fd..1bd3c49 100644
--- a/services/network/public/cpp/cors/cors_unittest.cc
+++ b/services/network/public/cpp/cors/cors_unittest.cc
@@ -4,27 +4,29 @@
 
 #include "services/network/public/cpp/cors/cors.h"
 
+#include <limits.h>
+
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 #include "url/origin.h"
 
 namespace network {
-
+namespace cors {
 namespace {
 
 using CORSTest = testing::Test;
 
 TEST_F(CORSTest, CheckAccessDetectsInvalidResponse) {
-  base::Optional<CORSErrorStatus> error_status = cors::CheckAccess(
-      GURL(), 0 /* response_status_code */,
-      base::nullopt /* allow_origin_header */,
-      base::nullopt /* allow_credentials_header */,
-      network::mojom::FetchCredentialsMode::kOmit, url::Origin());
+  base::Optional<CORSErrorStatus> error_status =
+      CheckAccess(GURL(), 0 /* response_status_code */,
+                  base::nullopt /* allow_origin_header */,
+                  base::nullopt /* allow_credentials_header */,
+                  network::mojom::FetchCredentialsMode::kOmit, url::Origin());
   ASSERT_TRUE(error_status);
   EXPECT_EQ(mojom::CORSError::kInvalidResponse, error_status->cors_error);
 }
 
-// Tests if cors::CheckAccess detects kWildcardOriginNotAllowed error correctly.
+// Tests if CheckAccess detects kWildcardOriginNotAllowed error correctly.
 TEST_F(CORSTest, CheckAccessDetectsWildcardOriginNotAllowed) {
   const GURL response_url("http://example.com/data");
   const url::Origin origin = url::Origin::Create(GURL("http://google.com"));
@@ -33,24 +35,24 @@
 
   // Access-Control-Allow-Origin '*' works.
   base::Optional<CORSErrorStatus> error1 =
-      cors::CheckAccess(response_url, response_status_code,
-                        allow_all_header /* allow_origin_header */,
-                        base::nullopt /* allow_credentials_header */,
-                        network::mojom::FetchCredentialsMode::kOmit, origin);
+      CheckAccess(response_url, response_status_code,
+                  allow_all_header /* allow_origin_header */,
+                  base::nullopt /* allow_credentials_header */,
+                  network::mojom::FetchCredentialsMode::kOmit, origin);
   EXPECT_FALSE(error1);
 
   // Access-Control-Allow-Origin '*' should not be allowed if credentials mode
   // is kInclude.
   base::Optional<CORSErrorStatus> error2 =
-      cors::CheckAccess(response_url, response_status_code,
-                        allow_all_header /* allow_origin_header */,
-                        base::nullopt /* allow_credentials_header */,
-                        network::mojom::FetchCredentialsMode::kInclude, origin);
+      CheckAccess(response_url, response_status_code,
+                  allow_all_header /* allow_origin_header */,
+                  base::nullopt /* allow_credentials_header */,
+                  network::mojom::FetchCredentialsMode::kInclude, origin);
   ASSERT_TRUE(error2);
   EXPECT_EQ(mojom::CORSError::kWildcardOriginNotAllowed, error2->cors_error);
 }
 
-// Tests if cors::CheckAccess detects kMissingAllowOriginHeader error correctly.
+// Tests if CheckAccess detects kMissingAllowOriginHeader error correctly.
 TEST_F(CORSTest, CheckAccessDetectsMissingAllowOriginHeader) {
   const GURL response_url("http://example.com/data");
   const url::Origin origin = url::Origin::Create(GURL("http://google.com"));
@@ -58,15 +60,15 @@
 
   // Access-Control-Allow-Origin is missed.
   base::Optional<CORSErrorStatus> error =
-      cors::CheckAccess(response_url, response_status_code,
-                        base::nullopt /* allow_origin_header */,
-                        base::nullopt /* allow_credentials_header */,
-                        network::mojom::FetchCredentialsMode::kOmit, origin);
+      CheckAccess(response_url, response_status_code,
+                  base::nullopt /* allow_origin_header */,
+                  base::nullopt /* allow_credentials_header */,
+                  network::mojom::FetchCredentialsMode::kOmit, origin);
   ASSERT_TRUE(error);
   EXPECT_EQ(mojom::CORSError::kMissingAllowOriginHeader, error->cors_error);
 }
 
-// Tests if cors::CheckAccess detects kMultipleAllowOriginValues error
+// Tests if CheckAccess detects kMultipleAllowOriginValues error
 // correctly.
 TEST_F(CORSTest, CheckAccessDetectsMultipleAllowOriginValues) {
   const GURL response_url("http://example.com/data");
@@ -75,55 +77,55 @@
 
   const std::string space_separated_multiple_origins(
       "http://example.com http://another.example.com");
-  base::Optional<CORSErrorStatus> error1 = cors::CheckAccess(
-      response_url, response_status_code,
-      space_separated_multiple_origins /* allow_origin_header */,
-      base::nullopt /* allow_credentials_header */,
-      network::mojom::FetchCredentialsMode::kOmit, origin);
+  base::Optional<CORSErrorStatus> error1 =
+      CheckAccess(response_url, response_status_code,
+                  space_separated_multiple_origins /* allow_origin_header */,
+                  base::nullopt /* allow_credentials_header */,
+                  network::mojom::FetchCredentialsMode::kOmit, origin);
   ASSERT_TRUE(error1);
   EXPECT_EQ(mojom::CORSError::kMultipleAllowOriginValues, error1->cors_error);
 
   const std::string comma_separated_multiple_origins(
       "http://example.com,http://another.example.com");
-  base::Optional<CORSErrorStatus> error2 = cors::CheckAccess(
-      response_url, response_status_code,
-      comma_separated_multiple_origins /* allow_origin_header */,
-      base::nullopt /* allow_credentials_header */,
-      network::mojom::FetchCredentialsMode::kOmit, origin);
+  base::Optional<CORSErrorStatus> error2 =
+      CheckAccess(response_url, response_status_code,
+                  comma_separated_multiple_origins /* allow_origin_header */,
+                  base::nullopt /* allow_credentials_header */,
+                  network::mojom::FetchCredentialsMode::kOmit, origin);
   ASSERT_TRUE(error2);
   EXPECT_EQ(mojom::CORSError::kMultipleAllowOriginValues, error2->cors_error);
 }
 
-// Tests if cors::CheckAccess detects kInvalidAllowOriginValue error correctly.
+// Tests if CheckAccess detects kInvalidAllowOriginValue error correctly.
 TEST_F(CORSTest, CheckAccessDetectsInvalidAllowOriginValue) {
   const GURL response_url("http://example.com/data");
   const url::Origin origin = url::Origin::Create(GURL("http://google.com"));
   const int response_status_code = 200;
 
   base::Optional<CORSErrorStatus> error =
-      cors::CheckAccess(response_url, response_status_code,
-                        std::string("invalid.origin") /* allow_origin_header */,
-                        base::nullopt /* allow_credentials_header */,
-                        network::mojom::FetchCredentialsMode::kOmit, origin);
+      CheckAccess(response_url, response_status_code,
+                  std::string("invalid.origin") /* allow_origin_header */,
+                  base::nullopt /* allow_credentials_header */,
+                  network::mojom::FetchCredentialsMode::kOmit, origin);
   ASSERT_TRUE(error);
   EXPECT_EQ(mojom::CORSError::kInvalidAllowOriginValue, error->cors_error);
   EXPECT_EQ("invalid.origin", error->failed_parameter);
 }
 
-// Tests if cors::CheckAccess detects kAllowOriginMismatch error correctly.
+// Tests if CheckAccess detects kAllowOriginMismatch error correctly.
 TEST_F(CORSTest, CheckAccessDetectsAllowOriginMismatch) {
   const GURL response_url("http://example.com/data");
   const url::Origin origin = url::Origin::Create(GURL("http://google.com"));
   const int response_status_code = 200;
 
   base::Optional<CORSErrorStatus> error1 =
-      cors::CheckAccess(response_url, response_status_code,
-                        origin.Serialize() /* allow_origin_header */,
-                        base::nullopt /* allow_credentials_header */,
-                        network::mojom::FetchCredentialsMode::kOmit, origin);
+      CheckAccess(response_url, response_status_code,
+                  origin.Serialize() /* allow_origin_header */,
+                  base::nullopt /* allow_credentials_header */,
+                  network::mojom::FetchCredentialsMode::kOmit, origin);
   ASSERT_FALSE(error1);
 
-  base::Optional<CORSErrorStatus> error2 = cors::CheckAccess(
+  base::Optional<CORSErrorStatus> error2 = CheckAccess(
       response_url, response_status_code,
       std::string("http://not.google.com") /* allow_origin_header */,
       base::nullopt /* allow_credentials_header */,
@@ -137,37 +139,37 @@
   const url::Origin null_origin;
   EXPECT_EQ(null_string, null_origin.Serialize());
 
-  base::Optional<CORSErrorStatus> error3 = cors::CheckAccess(
+  base::Optional<CORSErrorStatus> error3 = CheckAccess(
       response_url, response_status_code, null_string /* allow_origin_header */,
       base::nullopt /* allow_credentials_header */,
       network::mojom::FetchCredentialsMode::kOmit, null_origin);
   EXPECT_FALSE(error3);
 }
 
-// Tests if cors::CheckAccess detects kInvalidAllowCredentials error correctly.
+// Tests if CheckAccess detects kInvalidAllowCredentials error correctly.
 TEST_F(CORSTest, CheckAccessDetectsInvalidAllowCredential) {
   const GURL response_url("http://example.com/data");
   const url::Origin origin = url::Origin::Create(GURL("http://google.com"));
   const int response_status_code = 200;
 
   base::Optional<CORSErrorStatus> error1 =
-      cors::CheckAccess(response_url, response_status_code,
-                        origin.Serialize() /* allow_origin_header */,
-                        std::string("true") /* allow_credentials_header */,
-                        network::mojom::FetchCredentialsMode::kInclude, origin);
+      CheckAccess(response_url, response_status_code,
+                  origin.Serialize() /* allow_origin_header */,
+                  std::string("true") /* allow_credentials_header */,
+                  network::mojom::FetchCredentialsMode::kInclude, origin);
   ASSERT_FALSE(error1);
 
   base::Optional<CORSErrorStatus> error2 =
-      cors::CheckAccess(response_url, response_status_code,
-                        origin.Serialize() /* allow_origin_header */,
-                        std::string("fuga") /* allow_credentials_header */,
-                        network::mojom::FetchCredentialsMode::kInclude, origin);
+      CheckAccess(response_url, response_status_code,
+                  origin.Serialize() /* allow_origin_header */,
+                  std::string("fuga") /* allow_credentials_header */,
+                  network::mojom::FetchCredentialsMode::kInclude, origin);
   ASSERT_TRUE(error2);
   EXPECT_EQ(mojom::CORSError::kInvalidAllowCredentials, error2->cors_error);
   EXPECT_EQ("fuga", error2->failed_parameter);
 }
 
-// Tests if cors::CheckRedirectLocation detects kCORSDisabledScheme and
+// Tests if CheckRedirectLocation detects kCORSDisabledScheme and
 // kRedirectContainsCredentials errors correctly.
 TEST_F(CORSTest, CheckRedirectLocation) {
   struct TestCase {
@@ -277,30 +279,30 @@
                  << ", tainted: " << test.tainted);
 
     EXPECT_EQ(test.expectation,
-              cors::CheckRedirectLocation(test.url, test.request_mode, origin,
-                                          test.cors_flag, test.tainted));
+              CheckRedirectLocation(test.url, test.request_mode, origin,
+                                    test.cors_flag, test.tainted));
   }
 }
 
 TEST_F(CORSTest, CheckPreflightDetectsErrors) {
-  EXPECT_FALSE(cors::CheckPreflight(200));
-  EXPECT_FALSE(cors::CheckPreflight(299));
+  EXPECT_FALSE(CheckPreflight(200));
+  EXPECT_FALSE(CheckPreflight(299));
 
-  base::Optional<mojom::CORSError> error1 = cors::CheckPreflight(300);
+  base::Optional<mojom::CORSError> error1 = CheckPreflight(300);
   ASSERT_TRUE(error1);
   EXPECT_EQ(mojom::CORSError::kPreflightInvalidStatus, *error1);
 
-  EXPECT_FALSE(cors::CheckExternalPreflight(std::string("true")));
+  EXPECT_FALSE(CheckExternalPreflight(std::string("true")));
 
   base::Optional<CORSErrorStatus> error2 =
-      cors::CheckExternalPreflight(base::nullopt);
+      CheckExternalPreflight(base::nullopt);
   ASSERT_TRUE(error2);
   EXPECT_EQ(mojom::CORSError::kPreflightMissingAllowExternal,
             error2->cors_error);
   EXPECT_EQ("", error2->failed_parameter);
 
   base::Optional<CORSErrorStatus> error3 =
-      cors::CheckExternalPreflight(std::string("TRUE"));
+      CheckExternalPreflight(std::string("TRUE"));
   ASSERT_TRUE(error3);
   EXPECT_EQ(mojom::CORSError::kPreflightInvalidAllowExternal,
             error3->cors_error);
@@ -318,148 +320,386 @@
 
   // CORS flag is false, same-origin request
   EXPECT_EQ(FetchResponseType::kBasic,
-            cors::CalculateResponseTainting(
+            CalculateResponseTainting(
                 same_origin_url, FetchRequestMode::kSameOrigin, origin, false));
   EXPECT_EQ(FetchResponseType::kBasic,
-            cors::CalculateResponseTainting(
+            CalculateResponseTainting(
                 same_origin_url, FetchRequestMode::kNoCORS, origin, false));
   EXPECT_EQ(FetchResponseType::kBasic,
-            cors::CalculateResponseTainting(
-                same_origin_url, FetchRequestMode::kCORS, origin, false));
+            CalculateResponseTainting(same_origin_url, FetchRequestMode::kCORS,
+                                      origin, false));
   EXPECT_EQ(FetchResponseType::kBasic,
-            cors::CalculateResponseTainting(
+            CalculateResponseTainting(
                 same_origin_url, FetchRequestMode::kCORSWithForcedPreflight,
                 origin, false));
   EXPECT_EQ(FetchResponseType::kBasic,
-            cors::CalculateResponseTainting(
+            CalculateResponseTainting(
                 same_origin_url, FetchRequestMode::kNavigate, origin, false));
 
   // CORS flag is false, cross-origin request
   EXPECT_EQ(FetchResponseType::kOpaque,
-            cors::CalculateResponseTainting(
+            CalculateResponseTainting(
                 cross_origin_url, FetchRequestMode::kNoCORS, origin, false));
   EXPECT_EQ(FetchResponseType::kBasic,
-            cors::CalculateResponseTainting(
+            CalculateResponseTainting(
                 cross_origin_url, FetchRequestMode::kNavigate, origin, false));
 
   // CORS flag is true, same-origin request
   EXPECT_EQ(FetchResponseType::kCORS,
-            cors::CalculateResponseTainting(
-                same_origin_url, FetchRequestMode::kCORS, origin, true));
+            CalculateResponseTainting(same_origin_url, FetchRequestMode::kCORS,
+                                      origin, true));
   EXPECT_EQ(FetchResponseType::kCORS,
-            cors::CalculateResponseTainting(
+            CalculateResponseTainting(
                 same_origin_url, FetchRequestMode::kCORSWithForcedPreflight,
                 origin, true));
 
   // CORS flag is true, cross-origin request
   EXPECT_EQ(FetchResponseType::kCORS,
-            cors::CalculateResponseTainting(
-                cross_origin_url, FetchRequestMode::kCORS, origin, true));
+            CalculateResponseTainting(cross_origin_url, FetchRequestMode::kCORS,
+                                      origin, true));
   EXPECT_EQ(FetchResponseType::kCORS,
-            cors::CalculateResponseTainting(
+            CalculateResponseTainting(
                 cross_origin_url, FetchRequestMode::kCORSWithForcedPreflight,
                 origin, true));
 
   // Origin is not provided.
   EXPECT_EQ(FetchResponseType::kBasic,
-            cors::CalculateResponseTainting(
+            CalculateResponseTainting(
                 same_origin_url, FetchRequestMode::kNoCORS, no_origin, false));
   EXPECT_EQ(
       FetchResponseType::kBasic,
-      cors::CalculateResponseTainting(
-          same_origin_url, FetchRequestMode::kNavigate, no_origin, false));
+      CalculateResponseTainting(same_origin_url, FetchRequestMode::kNavigate,
+                                no_origin, false));
   EXPECT_EQ(FetchResponseType::kBasic,
-            cors::CalculateResponseTainting(
+            CalculateResponseTainting(
                 cross_origin_url, FetchRequestMode::kNoCORS, no_origin, false));
   EXPECT_EQ(
       FetchResponseType::kBasic,
-      cors::CalculateResponseTainting(
-          cross_origin_url, FetchRequestMode::kNavigate, no_origin, false));
+      CalculateResponseTainting(cross_origin_url, FetchRequestMode::kNavigate,
+                                no_origin, false));
 }
 
-TEST_F(CORSTest, CheckCORSSafelist) {
+TEST_F(CORSTest, SafelistedMethod) {
   // Method check should be case-insensitive.
-  EXPECT_TRUE(cors::IsCORSSafelistedMethod("get"));
-  EXPECT_TRUE(cors::IsCORSSafelistedMethod("Get"));
-  EXPECT_TRUE(cors::IsCORSSafelistedMethod("GET"));
-  EXPECT_TRUE(cors::IsCORSSafelistedMethod("HEAD"));
-  EXPECT_TRUE(cors::IsCORSSafelistedMethod("POST"));
-  EXPECT_FALSE(cors::IsCORSSafelistedMethod("OPTIONS"));
+  EXPECT_TRUE(IsCORSSafelistedMethod("get"));
+  EXPECT_TRUE(IsCORSSafelistedMethod("Get"));
+  EXPECT_TRUE(IsCORSSafelistedMethod("GET"));
+  EXPECT_TRUE(IsCORSSafelistedMethod("HEAD"));
+  EXPECT_TRUE(IsCORSSafelistedMethod("POST"));
+  EXPECT_FALSE(IsCORSSafelistedMethod("OPTIONS"));
+}
 
-  // Content-Type check should be case-insensitive, and should ignore spaces and
-  // parameters such as charset after a semicolon.
+TEST_F(CORSTest, SafelistedHeader) {
+  // See SafelistedAccept/AcceptLanguage/ContentLanguage/ContentType also.
+
+  EXPECT_TRUE(IsCORSSafelistedHeader("accept", "foo"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("foo", "bar"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("user-agent", "foo"));
+}
+
+TEST_F(CORSTest, SafelistedAccept) {
+  EXPECT_TRUE(IsCORSSafelistedHeader("accept", "text/html"));
+  EXPECT_TRUE(IsCORSSafelistedHeader("AccepT", "text/html"));
+
+  constexpr char kAllowed[] =
+      "\t !#$%&'*+,-./0123456789;="
+      "ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~";
+  for (int i = CHAR_MIN; i <= CHAR_MAX; ++i) {
+    SCOPED_TRACE(testing::Message() << "c = static_cast<char>(" << i << ")");
+    char c = static_cast<char>(i);
+    // 1 for the trailing null character.
+    auto* end = kAllowed + base::size(kAllowed) - 1;
+    EXPECT_EQ(std::find(kAllowed, end, c) != end,
+              IsCORSSafelistedHeader("accept", std::string(1, c)));
+    EXPECT_EQ(std::find(kAllowed, end, c) != end,
+              IsCORSSafelistedHeader("AccepT", std::string(1, c)));
+  }
+
+  EXPECT_TRUE(IsCORSSafelistedHeader("accept", std::string(128, 'a')));
+  EXPECT_FALSE(IsCORSSafelistedHeader("accept", std::string(129, 'a')));
+  EXPECT_TRUE(IsCORSSafelistedHeader("AccepT", std::string(128, 'a')));
+  EXPECT_FALSE(IsCORSSafelistedHeader("AccepT", std::string(129, 'a')));
+}
+
+TEST_F(CORSTest, SafelistedAcceptLanguage) {
+  EXPECT_TRUE(IsCORSSafelistedHeader("accept-language", "en,ja"));
+  EXPECT_TRUE(IsCORSSafelistedHeader("aCcEPT-lAngUAge", "en,ja"));
+
+  constexpr char kAllowed[] =
+      "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz *,-.;=";
+  for (int i = CHAR_MIN; i <= CHAR_MAX; ++i) {
+    SCOPED_TRACE(testing::Message() << "c = static_cast<char>(" << i << ")");
+    char c = static_cast<char>(i);
+    // 1 for the trailing null character.
+    auto* end = kAllowed + base::size(kAllowed) - 1;
+    EXPECT_EQ(std::find(kAllowed, end, c) != end,
+              IsCORSSafelistedHeader("aCcEPT-lAngUAge", std::string(1, c)));
+  }
+  EXPECT_TRUE(IsCORSSafelistedHeader("accept-language", std::string(128, 'a')));
+  EXPECT_FALSE(
+      IsCORSSafelistedHeader("accept-language", std::string(129, 'a')));
+  EXPECT_TRUE(IsCORSSafelistedHeader("aCcEPT-lAngUAge", std::string(128, 'a')));
+  EXPECT_FALSE(
+      IsCORSSafelistedHeader("aCcEPT-lAngUAge", std::string(129, 'a')));
+}
+
+TEST_F(CORSTest, SafelistedContentLanguage) {
+  EXPECT_TRUE(IsCORSSafelistedHeader("content-language", "en,ja"));
+  EXPECT_TRUE(IsCORSSafelistedHeader("cONTent-LANguaGe", "en,ja"));
+
+  constexpr char kAllowed[] =
+      "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz *,-.;=";
+  for (int i = CHAR_MIN; i <= CHAR_MAX; ++i) {
+    SCOPED_TRACE(testing::Message() << "c = static_cast<char>(" << i << ")");
+    char c = static_cast<char>(i);
+    // 1 for the trailing null character.
+    auto* end = kAllowed + base::size(kAllowed) - 1;
+    EXPECT_EQ(std::find(kAllowed, end, c) != end,
+              IsCORSSafelistedHeader("content-language", std::string(1, c)));
+    EXPECT_EQ(std::find(kAllowed, end, c) != end,
+              IsCORSSafelistedHeader("cONTent-LANguaGe", std::string(1, c)));
+  }
   EXPECT_TRUE(
-      cors::IsCORSSafelistedContentType("application/x-www-form-urlencoded"));
-  EXPECT_TRUE(cors::IsCORSSafelistedContentType("multipart/form-data"));
-  EXPECT_TRUE(cors::IsCORSSafelistedContentType("text/plain"));
-  EXPECT_TRUE(cors::IsCORSSafelistedContentType("TEXT/PLAIN"));
-  EXPECT_TRUE(cors::IsCORSSafelistedContentType("text/plain;charset=utf-8"));
-  EXPECT_TRUE(cors::IsCORSSafelistedContentType(" text/plain ;charset=utf-8"));
-  EXPECT_FALSE(cors::IsCORSSafelistedContentType("text/html"));
+      IsCORSSafelistedHeader("content-language", std::string(128, 'a')));
+  EXPECT_FALSE(
+      IsCORSSafelistedHeader("content-language", std::string(129, 'a')));
+  EXPECT_TRUE(
+      IsCORSSafelistedHeader("cONTent-LANguaGe", std::string(128, 'a')));
+  EXPECT_FALSE(
+      IsCORSSafelistedHeader("cONTent-LANguaGe", std::string(129, 'a')));
+}
 
-  // Header check should be case-insensitive. Value must be considered only for
-  // Content-Type.
-  EXPECT_TRUE(cors::IsCORSSafelistedHeader("accept", "text/html"));
-  EXPECT_TRUE(cors::IsCORSSafelistedHeader("Accept-Language", "en"));
-  EXPECT_TRUE(cors::IsCORSSafelistedHeader("Content-Language", "ja"));
-  EXPECT_TRUE(cors::IsCORSSafelistedHeader("SAVE-DATA", "on"));
-  EXPECT_TRUE(cors::IsCORSSafelistedHeader("Intervention", ""));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("Cache-Control", ""));
-  EXPECT_TRUE(cors::IsCORSSafelistedHeader("Content-Type", "text/plain"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("Content-Type", "image/png"));
+TEST_F(CORSTest, SafelistedContentType) {
+  EXPECT_TRUE(IsCORSSafelistedHeader("content-type", "text/plain"));
+  EXPECT_TRUE(IsCORSSafelistedHeader("CoNtEnt-TyPE", "text/plain"));
+  EXPECT_TRUE(
+      IsCORSSafelistedHeader("content-type", "text/plain; charset=utf-8"));
+  EXPECT_TRUE(
+      IsCORSSafelistedHeader("content-type", "  text/plain ; charset=UTF-8"));
+  EXPECT_TRUE(
+      IsCORSSafelistedHeader("content-type", "text/plain; param=BOGUS"));
+  EXPECT_TRUE(IsCORSSafelistedHeader("content-type",
+                                     "application/x-www-form-urlencoded"));
+  EXPECT_TRUE(IsCORSSafelistedHeader("content-type", "multipart/form-data"));
+
+  EXPECT_TRUE(IsCORSSafelistedHeader("content-type", "Text/plain"));
+  EXPECT_TRUE(IsCORSSafelistedHeader("content-type", "tEXT/PLAIN"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("content-type", "text/html"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("CoNtEnt-TyPE", "text/html"));
+
+  EXPECT_FALSE(IsCORSSafelistedHeader("content-type", "image/png"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("CoNtEnt-TyPE", "image/png"));
+  EXPECT_TRUE(IsCORSSafelistedHeader(
+      "content-type", "text/plain; charset=" + std::string(108, 'a')));
+  EXPECT_TRUE(IsCORSSafelistedHeader(
+      "cONTent-tYPE", "text/plain; charset=" + std::string(108, 'a')));
+  EXPECT_FALSE(IsCORSSafelistedHeader(
+      "content-type", "text/plain; charset=" + std::string(109, 'a')));
+  EXPECT_FALSE(IsCORSSafelistedHeader(
+      "cONTent-tYPE", "text/plain; charset=" + std::string(109, 'a')));
 }
 
 TEST_F(CORSTest, CheckCORSClientHintsSafelist) {
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("device-memory", ""));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("device-memory", "abc"));
-  EXPECT_TRUE(cors::IsCORSSafelistedHeader("device-memory", "1.25"));
-  EXPECT_TRUE(cors::IsCORSSafelistedHeader("DEVICE-memory", "1.25"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("device-memory", "1.25-2.5"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("device-memory", "-1.25"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("device-memory", "1e2"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("device-memory", "inf"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("device-memory", "-2.3"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("device-memory", "NaN"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("DEVICE-memory", "1.25.3"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("DEVICE-memory", "1."));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("DEVICE-memory", ".1"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("DEVICE-memory", "."));
-  EXPECT_TRUE(cors::IsCORSSafelistedHeader("DEVICE-memory", "1"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("device-memory", ""));
+  EXPECT_FALSE(IsCORSSafelistedHeader("device-memory", "abc"));
+  EXPECT_TRUE(IsCORSSafelistedHeader("device-memory", "1.25"));
+  EXPECT_TRUE(IsCORSSafelistedHeader("DEVICE-memory", "1.25"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("device-memory", "1.25-2.5"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("device-memory", "-1.25"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("device-memory", "1e2"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("device-memory", "inf"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("device-memory", "-2.3"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("device-memory", "NaN"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("DEVICE-memory", "1.25.3"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("DEVICE-memory", "1."));
+  EXPECT_FALSE(IsCORSSafelistedHeader("DEVICE-memory", ".1"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("DEVICE-memory", "."));
+  EXPECT_TRUE(IsCORSSafelistedHeader("DEVICE-memory", "1"));
 
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("dpr", ""));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("dpr", "abc"));
-  EXPECT_TRUE(cors::IsCORSSafelistedHeader("dpr", "1.25"));
-  EXPECT_TRUE(cors::IsCORSSafelistedHeader("Dpr", "1.25"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("dpr", "1.25-2.5"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("dpr", "-1.25"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("dpr", "1e2"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("dpr", "inf"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("dpr", "-2.3"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("dpr", "NaN"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("dpr", "1.25.3"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("dpr", "1."));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("dpr", ".1"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("dpr", "."));
-  EXPECT_TRUE(cors::IsCORSSafelistedHeader("dpr", "1"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("dpr", ""));
+  EXPECT_FALSE(IsCORSSafelistedHeader("dpr", "abc"));
+  EXPECT_TRUE(IsCORSSafelistedHeader("dpr", "1.25"));
+  EXPECT_TRUE(IsCORSSafelistedHeader("Dpr", "1.25"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("dpr", "1.25-2.5"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("dpr", "-1.25"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("dpr", "1e2"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("dpr", "inf"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("dpr", "-2.3"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("dpr", "NaN"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("dpr", "1.25.3"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("dpr", "1."));
+  EXPECT_FALSE(IsCORSSafelistedHeader("dpr", ".1"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("dpr", "."));
+  EXPECT_TRUE(IsCORSSafelistedHeader("dpr", "1"));
 
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("width", ""));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("width", "abc"));
-  EXPECT_TRUE(cors::IsCORSSafelistedHeader("width", "125"));
-  EXPECT_TRUE(cors::IsCORSSafelistedHeader("width", "1"));
-  EXPECT_TRUE(cors::IsCORSSafelistedHeader("WIDTH", "125"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("width", "125.2"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("width", "-125"));
-  EXPECT_TRUE(cors::IsCORSSafelistedHeader("width", "2147483648"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("width", ""));
+  EXPECT_FALSE(IsCORSSafelistedHeader("width", "abc"));
+  EXPECT_TRUE(IsCORSSafelistedHeader("width", "125"));
+  EXPECT_TRUE(IsCORSSafelistedHeader("width", "1"));
+  EXPECT_TRUE(IsCORSSafelistedHeader("WIDTH", "125"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("width", "125.2"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("width", "-125"));
+  EXPECT_TRUE(IsCORSSafelistedHeader("width", "2147483648"));
 
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("viewport-width", ""));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("viewport-width", "abc"));
-  EXPECT_TRUE(cors::IsCORSSafelistedHeader("viewport-width", "125"));
-  EXPECT_TRUE(cors::IsCORSSafelistedHeader("viewport-width", "1"));
-  EXPECT_TRUE(cors::IsCORSSafelistedHeader("viewport-Width", "125"));
-  EXPECT_FALSE(cors::IsCORSSafelistedHeader("viewport-width", "125.2"));
-  EXPECT_TRUE(cors::IsCORSSafelistedHeader("viewport-width", "2147483648"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("viewport-width", ""));
+  EXPECT_FALSE(IsCORSSafelistedHeader("viewport-width", "abc"));
+  EXPECT_TRUE(IsCORSSafelistedHeader("viewport-width", "125"));
+  EXPECT_TRUE(IsCORSSafelistedHeader("viewport-width", "1"));
+  EXPECT_TRUE(IsCORSSafelistedHeader("viewport-Width", "125"));
+  EXPECT_FALSE(IsCORSSafelistedHeader("viewport-width", "125.2"));
+  EXPECT_TRUE(IsCORSSafelistedHeader("viewport-width", "2147483648"));
+}
+
+TEST_F(CORSTest, CORSUnsafeRequestHeaderNames) {
+  // Needed because initializer list is not allowed for a macro argument.
+  using List = std::vector<std::string>;
+
+  // Empty => Empty
+  EXPECT_EQ(CORSUnsafeRequestHeaderNames({}), List({}));
+
+  // Some headers are safelisted.
+  EXPECT_EQ(CORSUnsafeRequestHeaderNames({{"content-type", "text/plain"},
+                                          {"dpr", "12345"},
+                                          {"aCCept", "en,ja"},
+                                          {"accept-charset", "utf-8"},
+                                          {"uSer-Agent", "foo"},
+                                          {"hogE", "fuga"}}),
+            List({"accept-charset", "user-agent", "hoge"}));
+
+  // All headers are not safelisted.
+  EXPECT_EQ(
+      CORSUnsafeRequestHeaderNames({{"content-type", "text/html"},
+                                    {"dpr", "123-45"},
+                                    {"aCCept", "en,ja"},
+                                    {"accept-charset", "utf-8"},
+                                    {"uSer-Agent", "foo"},
+                                    {"hogE", "fuga"}}),
+      List({"content-type", "dpr", "accept-charset", "user-agent", "hoge"}));
+
+  // |safelistValueSize| is 1024.
+  EXPECT_EQ(
+      CORSUnsafeRequestHeaderNames(
+          {{"content-type", "text/plain; charset=" + std::string(108, '1')},
+           {"accept", std::string(128, '1')},
+           {"accept-language", std::string(128, '1')},
+           {"content-language", std::string(128, '1')},
+           {"dpr", std::string(128, '1')},
+           {"device-memory", std::string(128, '1')},
+           {"save-data", "on"},
+           {"viewport-width", std::string(128, '1')},
+           {"width", std::string(126, '1')},
+           {"hogE", "fuga"}}),
+      List({"hoge"}));
+
+  // |safelistValueSize| is 1025.
+  EXPECT_EQ(
+      CORSUnsafeRequestHeaderNames(
+          {{"content-type", "text/plain; charset=" + std::string(108, '1')},
+           {"accept", std::string(128, '1')},
+           {"accept-language", std::string(128, '1')},
+           {"content-language", std::string(128, '1')},
+           {"dpr", std::string(128, '1')},
+           {"device-memory", std::string(128, '1')},
+           {"save-data", "on"},
+           {"viewport-width", std::string(128, '1')},
+           {"width", std::string(127, '1')},
+           {"hogE", "fuga"}}),
+      List({"hoge", "content-type", "accept", "accept-language",
+            "content-language", "dpr", "device-memory", "save-data",
+            "viewport-width", "width"}));
+
+  // |safelistValueSize| is 897 because "content-type" is not safelisted.
+  EXPECT_EQ(
+      CORSUnsafeRequestHeaderNames(
+          {{"content-type", "text/plain; charset=" + std::string(128, '1')},
+           {"accept", std::string(128, '1')},
+           {"accept-language", std::string(128, '1')},
+           {"content-language", std::string(128, '1')},
+           {"dpr", std::string(128, '1')},
+           {"device-memory", std::string(128, '1')},
+           {"save-data", "on"},
+           {"viewport-width", std::string(128, '1')},
+           {"width", std::string(127, '1')},
+           {"hogE", "fuga"}}),
+      List({"content-type", "hoge"}));
+}
+
+TEST_F(CORSTest, CORSUnsafeNotForbiddenRequestHeaderNames) {
+  // Needed because initializer list is not allowed for a macro argument.
+  using List = std::vector<std::string>;
+
+  // Empty => Empty
+  EXPECT_EQ(CORSUnsafeNotForbiddenRequestHeaderNames({}), List({}));
+
+  // "user-agent" is NOT forbidden per spec, but forbidden in Chromium.
+  EXPECT_EQ(
+      CORSUnsafeNotForbiddenRequestHeaderNames({{"content-type", "text/plain"},
+                                                {"dpr", "12345"},
+                                                {"aCCept", "en,ja"},
+                                                {"accept-charset", "utf-8"},
+                                                {"uSer-Agent", "foo"},
+                                                {"hogE", "fuga"}}),
+      List({"hoge"}));
+
+  EXPECT_EQ(
+      CORSUnsafeNotForbiddenRequestHeaderNames({{"content-type", "text/html"},
+                                                {"dpr", "123-45"},
+                                                {"aCCept", "en,ja"},
+                                                {"accept-charset", "utf-8"},
+                                                {"hogE", "fuga"}}),
+      List({"content-type", "dpr", "hoge"}));
+
+  // |safelistValueSize| is 1024.
+  EXPECT_EQ(
+      CORSUnsafeNotForbiddenRequestHeaderNames(
+          {{"content-type", "text/plain; charset=" + std::string(108, '1')},
+           {"accept", std::string(128, '1')},
+           {"accept-language", std::string(128, '1')},
+           {"content-language", std::string(128, '1')},
+           {"dpr", std::string(128, '1')},
+           {"device-memory", std::string(128, '1')},
+           {"save-data", "on"},
+           {"viewport-width", std::string(128, '1')},
+           {"width", std::string(126, '1')},
+           {"accept-charset", "utf-8"},
+           {"hogE", "fuga"}}),
+      List({"hoge"}));
+
+  // |safelistValueSize| is 1025.
+  EXPECT_EQ(
+      CORSUnsafeNotForbiddenRequestHeaderNames(
+          {{"content-type", "text/plain; charset=" + std::string(108, '1')},
+           {"accept", std::string(128, '1')},
+           {"accept-language", std::string(128, '1')},
+           {"content-language", std::string(128, '1')},
+           {"dpr", std::string(128, '1')},
+           {"device-memory", std::string(128, '1')},
+           {"save-data", "on"},
+           {"viewport-width", std::string(128, '1')},
+           {"width", std::string(127, '1')},
+           {"accept-charset", "utf-8"},
+           {"hogE", "fuga"}}),
+      List({"hoge", "content-type", "accept", "accept-language",
+            "content-language", "dpr", "device-memory", "save-data",
+            "viewport-width", "width"}));
+
+  // |safelistValueSize| is 897 because "content-type" is not safelisted.
+  EXPECT_EQ(
+      CORSUnsafeNotForbiddenRequestHeaderNames(
+          {{"content-type", "text/plain; charset=" + std::string(128, '1')},
+           {"accept", std::string(128, '1')},
+           {"accept-language", std::string(128, '1')},
+           {"content-language", std::string(128, '1')},
+           {"dpr", std::string(128, '1')},
+           {"device-memory", std::string(128, '1')},
+           {"save-data", "on"},
+           {"viewport-width", std::string(128, '1')},
+           {"width", std::string(127, '1')},
+           {"accept-charset", "utf-8"},
+           {"hogE", "fuga"}}),
+      List({"content-type", "hoge"}));
 }
 
 }  // namespace
-
+}  // namespace cors
 }  // namespace network
diff --git a/services/network/public/cpp/cors/preflight_result.cc b/services/network/public/cpp/cors/preflight_result.cc
index 3cf0f25..516e7ef7 100644
--- a/services/network/public/cpp/cors/preflight_result.cc
+++ b/services/network/public/cpp/cors/preflight_result.cc
@@ -136,20 +136,17 @@
   if (!credentials_ && headers_.find("*") != headers_.end())
     return base::nullopt;
 
-  for (const auto& header : headers.GetHeaderVector()) {
+  // Forbidden headers are forbidden to be used by JavaScript, and checked
+  // beforehand. But user-agents may add these headers internally, and it's
+  // fine.
+  for (const auto& name :
+       CORSUnsafeNotForbiddenRequestHeaderNames(headers.GetHeaderVector())) {
     // Header list check is performed in case-insensitive way. Here, we have a
     // parsed header list set in lower case, and search each header in lower
     // case.
-    const std::string key = base::ToLowerASCII(header.key);
-    if (headers_.find(key) == headers_.end() &&
-        !IsCORSSafelistedHeader(key, header.value)) {
-      // Forbidden headers are forbidden to be used by JavaScript, and checked
-      // beforehand. But user-agents may add these headers internally, and it's
-      // fine.
-      if (IsForbiddenHeader(key))
-        continue;
+    if (headers_.find(name) == headers_.end()) {
       return CORSErrorStatus(
-          mojom::CORSError::kHeaderDisallowedByPreflightResponse, header.key);
+          mojom::CORSError::kHeaderDisallowedByPreflightResponse, name);
     }
   }
   return base::nullopt;
diff --git a/services/network/public/cpp/cors/preflight_result_unittest.cc b/services/network/public/cpp/cors/preflight_result_unittest.cc
index 2a83e34af..b7084eb 100644
--- a/services/network/public/cpp/cors/preflight_result_unittest.cc
+++ b/services/network/public/cpp/cors/preflight_result_unittest.cc
@@ -135,15 +135,15 @@
     {"GET", "", mojom::FetchCredentialsMode::kOmit, "GET", "X-MY-HEADER:t",
      mojom::FetchCredentialsMode::kOmit,
      CORSErrorStatus(mojom::CORSError::kHeaderDisallowedByPreflightResponse,
-                     "X-MY-HEADER")},
+                     "x-my-header")},
     {"GET", "X-SOME-OTHER-HEADER", mojom::FetchCredentialsMode::kOmit, "GET",
      "X-MY-HEADER:t", mojom::FetchCredentialsMode::kOmit,
      CORSErrorStatus(mojom::CORSError::kHeaderDisallowedByPreflightResponse,
-                     "X-MY-HEADER")},
+                     "x-my-header")},
     {"GET", "X-MY-HEADER", mojom::FetchCredentialsMode::kOmit, "GET",
      "X-MY-HEADER:t\r\nY-MY-HEADER:t", mojom::FetchCredentialsMode::kOmit,
      CORSErrorStatus(mojom::CORSError::kHeaderDisallowedByPreflightResponse,
-                     "Y-MY-HEADER")},
+                     "y-my-header")},
 };
 
 TEST_F(PreflightResultTest, MaxAge) {
diff --git a/services/network/public/cpp/network_ipc_param_traits.h b/services/network/public/cpp/network_ipc_param_traits.h
index 0444806..9f374e4 100644
--- a/services/network/public/cpp/network_ipc_param_traits.h
+++ b/services/network/public/cpp/network_ipc_param_traits.h
@@ -207,6 +207,7 @@
   IPC_STRUCT_TRAITS_MEMBER(cors_exposed_header_names)
   IPC_STRUCT_TRAITS_MEMBER(async_revalidation_requested)
   IPC_STRUCT_TRAITS_MEMBER(did_mime_sniff)
+  IPC_STRUCT_TRAITS_MEMBER(is_signed_exchange_inner_response)
 IPC_STRUCT_TRAITS_END()
 
 IPC_ENUM_TRAITS_MAX_VALUE(network::mojom::FetchResponseType,
diff --git a/services/network/public/cpp/resource_response.cc b/services/network/public/cpp/resource_response.cc
index d00c077..21028e4 100644
--- a/services/network/public/cpp/resource_response.cc
+++ b/services/network/public/cpp/resource_response.cc
@@ -61,6 +61,8 @@
   new_response->head.async_revalidation_requested =
       head.async_revalidation_requested;
   new_response->head.did_mime_sniff = head.did_mime_sniff;
+  new_response->head.is_signed_exchange_inner_response =
+      head.is_signed_exchange_inner_response;
   return new_response;
 }
 
diff --git a/services/network/public/cpp/resource_response_info.h b/services/network/public/cpp/resource_response_info.h
index 5b12bf3..e6b3b30 100644
--- a/services/network/public/cpp/resource_response_info.h
+++ b/services/network/public/cpp/resource_response_info.h
@@ -185,6 +185,9 @@
   // mime sniffing anymore.
   bool did_mime_sniff;
 
+  // True if the response is an inner response of a signed exchange.
+  bool is_signed_exchange_inner_response = false;
+
   // NOTE: When adding or changing fields here, also update
   // ResourceResponse::DeepCopy in resource_response.cc.
 };
diff --git a/services/service_manager/sandbox/mac/renderer_v2.sb b/services/service_manager/sandbox/mac/renderer_v2.sb
index 3501044..4211576 100644
--- a/services/service_manager/sandbox/mac/renderer_v2.sb
+++ b/services/service_manager/sandbox/mac/renderer_v2.sb
@@ -69,5 +69,4 @@
   ; https://crbug.com/850021
   (global-name "com.apple.cvmsServ")
   ; crbug.com/792217
-  (global-name "com.apple.system.notification_center")
-  (global-name "com.apple.windowserver.active"))
+  (global-name "com.apple.system.notification_center"))
diff --git a/testing/buildbot/filters/chromeos.single_process_mash.fyi.browser_tests.filter b/testing/buildbot/filters/chromeos.single_process_mash.fyi.browser_tests.filter
index 55f4a1a..f34dbaa 100644
--- a/testing/buildbot/filters/chromeos.single_process_mash.fyi.browser_tests.filter
+++ b/testing/buildbot/filters/chromeos.single_process_mash.fyi.browser_tests.filter
@@ -1,277 +1,35 @@
 # These tests currently fail with SingleProcessMash enabled.
 # Bug: crbug.com/877118
 
-# Uses ash::WindowState in browser process.
--AcceleratorCommandsBrowserTest.ToggleMaximized
+# --------------------------------------------------
+# Tests that are also blacklisted for Mash.
+# --------------------------------------------------
 
-# Crashes on exit, even without SingleProcessMash.
--AffiliationCheck/EnterpriseDeviceAttributesTest.Success/Affiliated
--AffiliationCheck/EnterpriseDeviceAttributesTest.Success/NotAffiliated
+# Extensive use of ash::WindowState.
+-InitiallyMaximized/AcceleratorCommandsFullscreenBrowserTest.*
+-InitiallyMaximized/AcceleratorCommandsPlatformAppFullscreenBrowserTest.*
+-InitiallyRestored/AcceleratorCommandsFullscreenBrowserTest.*
+-InitiallyRestored/AcceleratorCommandsPlatformAppFullscreenBrowserTest.*
 
-# Also fails in mash, https://crbug.com/855767
--AppWindowApiTest.OnRestoredEvent
+# Virtual keyboard not supported.
+-DefaultKeyboardExtensionBrowserTest.*
+-KeyboardEndToEndTest.*
+-KioskVirtualKeyboardTest.*
+-VirtualKeyboardAppWindowTest.*
+-VirtualKeyboardStateTest.*
+-VirtualKeyboardWebContentTest.*
 
-# Automation API tests.
--AutomationApiTest.DesktopActions
--AutomationApiTest.DesktopFocusViews
--AutomationApiTest.DesktopFocusWeb
--AutomationApiTest.DesktopHitTest
--AutomationApiTest.LocationInWebView
--AutomationApiTestWithDeviceScaleFactor.HitTest
--AutomationApiTestWithDeviceScaleFactor.LocationScaled
+# AutomationManagerAura::Enable() uses ash to get active window. More generally,
+# chrome a11y code directly accesses ash system UI widgets and views.
+-AutomationApiTest.*
+-AutomationApiTestWithDeviceScaleFactor.*
+-AutomationManagerAuraBrowserTest.*
 
-# Automation manager tests.
--AutomationManagerAuraBrowserTest.WebAppearsOnce
-
-# Flaky tests. crbug.com/880584
--AutoplayMetricsBrowserTest.RecordAutoplayAttemptUkm
-
-# Blub Arc tests.
--Blub/UnaffiliatedArcAllowedTest.ProfileTest/0
--Blub/UnaffiliatedArcAllowedTest.ProfileTest/1
-
-# PictureinPicture does not work with mash because VideoSurfaceLayer is
-# disabled. https://crbug.com/827327
--BrowserActionApiTest.TestPictureInPictureOnBrowserActionIconClick
-
-# Browser command controller tests.
--BrowserCommandControllerBrowserTest.LockedFullscreen
-
-# Browser frame view tests.
--BrowserNonClientFrameViewAshTest.AvatarDisplayOnTeleportedWindow/material
--BrowserNonClientFrameViewAshTest.AvatarDisplayOnTeleportedWindow/material_refresh
--BrowserNonClientFrameViewAshTest.AvatarDisplayOnTeleportedWindow/material_touch_optimized
--BrowserNonClientFrameViewAshTest.ImmersiveModeTopViewInset/material
--BrowserNonClientFrameViewAshTest.ImmersiveModeTopViewInset/material_refresh
--BrowserNonClientFrameViewAshTest.ImmersiveModeTopViewInset/material_touch_optimized
-
-# Cast tests.
--CastMirroringServiceHostBrowserTest.CaptureTabVideo
--CastStreamingApiTestWithPixelOutput.EndToEnd/0
-
-# Enterprise keys tests.
--CheckSystemTokenAvailability/EnterprisePlatformKeysTest.Basic/0
--CheckSystemTokenAvailability/EnterprisePlatformKeysTest.Basic/1
--CheckSystemTokenAvailability/EnterprisePlatformKeysTest.Basic/2
--CheckSystemTokenAvailability/EnterprisePlatformKeysTest.Basic/3
-
-# Find in PDF tests.
--ChromeFindRequestManagerTest.FindInPDF
-
-# Ash native views tests.
--ChromeNativeAppWindowViewsAuraAshBrowserTest.ImmersiveModeFullscreenRestoreType
--ChromeNativeAppWindowViewsAuraAshBrowserTest.ImmersiveWorkFlow
--ChromeNativeAppWindowViewsAuraAshBrowserTest.NoImmersiveModeWhenForcedFullscreen
--ChromeNativeAppWindowViewsAuraAshBrowserTest.PublicSessionImmersiveMode
--ChromeNativeAppWindowViewsAuraAshBrowserTest.RestoreImmersiveMode
-
-# Chrome OS stylus tests.
--ChromeOSInfoPrivateTest.StylusSeen
-
-# Context menu tests.
--ContextMenuBrowserTest.ContextMenuEntriesAreDisabledInLockedFullscreen
-
-# PictureinPicture does not work with mash because VideoSurfaceLayer is
-# disabled. https://crbug.com/827327
--ControlPictureInPictureWindowControllerBrowserTest.PictureInPictureAddControlAndFireEvent
--ControlPictureInPictureWindowControllerBrowserTest.PictureInPictureAddTwoControlsAndFireLeftEvent
--ControlPictureInPictureWindowControllerBrowserTest.PictureInPictureAddTwoControlsAndFireRightEvent
--ControlPictureInPictureWindowControllerBrowserTest.PictureInPictureControlEventFired
-
-# Default extension tests.
--DefaultKeyboardExtensionBrowserTest.EndToEndTest
--DefaultKeyboardExtensionBrowserTest.IsKeyboardLoaded
--DefaultProfileExtensionBrowserTest.NoExtensionHosts
-
-# Logout reminder tests.
--DeviceLocalAccountTest.LastWindowClosedLogoutReminder
-
-# Immersive mode tests.
--ImmersiveModeBrowserViewTest.TabNavigationAcceleratorsFullscreenBrowser/material
--ImmersiveModeBrowserViewTest.TestCaptionButtonsReceiveEventsInAppImmersiveMode/material
--ImmersiveModeBrowserViewTest.TestCaptionButtonsReceiveEventsInAppImmersiveMode/material_refresh
--ImmersiveModeBrowserViewTest.TestCaptionButtonsReceiveEventsInAppImmersiveMode/material_touch_optimized
--ImmersiveModeBrowserViewTest.TestCaptionButtonsReceiveEventsInBrowserImmersiveMode/material
--ImmersiveModeBrowserViewTest.TestCaptionButtonsReceiveEventsInBrowserImmersiveMode/material_refresh
--ImmersiveModeBrowserViewTest.TestCaptionButtonsReceiveEventsInBrowserImmersiveMode/material_touch_optimized
-
-# Accelerator tests.
--InitiallyMaximized/AcceleratorCommandsFullscreenBrowserTest.ToggleFullscreen/0
--InitiallyMaximized/AcceleratorCommandsPlatformAppFullscreenBrowserTest.ToggleFullscreen/0
--InitiallyRestored/AcceleratorCommandsFullscreenBrowserTest.ToggleFullscreen/0
--InitiallyRestored/AcceleratorCommandsPlatformAppFullscreenBrowserTest.ToggleFullscreen/0
-
-# Keyboard tests.
--KeyboardEndToEndTest.OpenIfFocusedOnClick
--KeyboardEndToEndTest.OpenOnlyOnSyncFocus
-
-# Timeout in extensions::ResultCatcher::GetNextResult().
--KioskVirtualKeyboardTest.RestrictFeatures
-
-# Launcher tests.
--LauncherPlatformAppBrowserTest.AltNumberAppsTabbing
--LauncherPlatformAppBrowserTest.PackagedAppClickBehaviorInMinimizeMode
-
-# Lock screen tests.
--LockScreenNoteTakingTest.Launch
-
-# Login screen tests.
--LoginFeedbackTest.Basic
--LoginScreenDefaultPolicyLoginScreenBrowsertest.DeviceLoginScreenDefaultHighContrastEnabled
--LoginScreenDefaultPolicyLoginScreenBrowsertest.DeviceLoginScreenDefaultLargeCursorEnabled
--LoginScreenDefaultPolicyLoginScreenBrowsertest.DeviceLoginScreenDefaultScreenMagnifierEnabled
--LoginScreenDefaultPolicyLoginScreenBrowsertest.DeviceLoginScreenDefaultSpokenFeedbackEnabled
--LoginScreenDefaultPolicyLoginScreenBrowsertest.DeviceLoginScreenDefaultVirtualKeyboardEnabled
--LoginScreenPolicyTest.DisableSupervisedUsers
-
-# PRE steps crash on shutdown.
-# FATAL:ref_counted.h(85)] Check failed: CalledOnValidSequence()
--ManagedWithoutPermission/ManagedWithoutPermissionPlatformKeysTest.CorporateKeyAccessBlocked/0
--ManagedWithoutPermission/ManagedWithoutPermissionPlatformKeysTest.CorporateKeyAccessBlocked/1
--ManagedWithoutPermission/ManagedWithoutPermissionPlatformKeysTest.CorporateKeyAccessBlocked/2
--ManagedWithoutPermission/ManagedWithoutPermissionPlatformKeysTest.UserPermissionsBlocked/0
--ManagedWithoutPermission/ManagedWithoutPermissionPlatformKeysTest.UserPermissionsBlocked/1
--ManagedWithoutPermission/ManagedWithoutPermissionPlatformKeysTest.UserPermissionsBlocked/2
--ManagedWithPermission/ManagedWithPermissionPlatformKeysTest.PolicyDoesGrantAccessToNonCorporateKey/0
--ManagedWithPermission/ManagedWithPermissionPlatformKeysTest.PolicyDoesGrantAccessToNonCorporateKey/1
--ManagedWithPermission/ManagedWithPermissionPlatformKeysTest.PolicyDoesGrantAccessToNonCorporateKey/2
--ManagedWithPermission/ManagedWithPermissionPlatformKeysTest.PolicyGrantsAccessToCorporateKey/0
--ManagedWithPermission/ManagedWithPermissionPlatformKeysTest.PolicyGrantsAccessToCorporateKey/1
--ManagedWithPermission/ManagedWithPermissionPlatformKeysTest.PolicyGrantsAccessToCorporateKey/2
-
-# Flaky tests. crbug.com/880584
--MSE_ClearKey/EncryptedMediaTest.Playback_Multiple_VideoAudio_WebM/0
-
-# Ash frame view tests.
--NonHomeLauncherBrowserNonClientFrameViewAshTest.HeaderHeightForSnappedBrowserInSplitView/material
--NonHomeLauncherBrowserNonClientFrameViewAshTest.HeaderHeightForSnappedBrowserInSplitView/material_refresh
--NonHomeLauncherBrowserNonClientFrameViewAshTest.HeaderHeightForSnappedBrowserInSplitView/material_touch_optimized
-
-# PDF extension tests.
--PDFExtensionHitTestTest.ContextMenuCoordinates/0
--PDFExtensionHitTestTest.ContextMenuCoordinates/1
--PDFExtensionHitTestTest.MouseLeave/0
--PDFExtensionHitTestTest.MouseLeave/1
--PDFExtensionTest.BasicPlugin
--PDFExtensionTest.PdfAccessibilitySelection
-
-# Picture-in-Picture does not work with mash because VideoSurfaceLayer is
-# disabled. https://crbug.com/827327
--PictureInPictureWindowControllerBrowserTest.CloseTwiceSideEffects
--PictureInPictureWindowControllerBrowserTest.CloseWindowFromWebAPIWhilePlaying
--PictureInPictureWindowControllerBrowserTest.CloseWindowNotifiesController
--PictureInPictureWindowControllerBrowserTest.CloseWindowWhilePlaying
--PictureInPictureWindowControllerBrowserTest.CloseWindowWithoutPlaying
--PictureInPictureWindowControllerBrowserTest.CreationAndVisibility
--PictureInPictureWindowControllerBrowserTest.CrossOriginFrameEnterLeaveCloseWindow
--PictureInPictureWindowControllerBrowserTest.EnterFullscreenThenPictureInPicture
--PictureInPictureWindowControllerBrowserTest.EnterMetadataPosterOptimisation
--PictureInPictureWindowControllerBrowserTest.EnterPictureInPictureThenFullscreen
--PictureInPictureWindowControllerBrowserTest.EnterPictureInPictureThenNavigateAwayCloseWindow
--PictureInPictureWindowControllerBrowserTest.EnterUsingControllerThenEnterUsingWebContents
--PictureInPictureWindowControllerBrowserTest.EnterUsingWebContentsThenUsingController
--PictureInPictureWindowControllerBrowserTest.FrameEnterLeaveClosesWindow
--PictureInPictureWindowControllerBrowserTest.MultipleBrowserWindowOnePIPWindow
--PictureInPictureWindowControllerBrowserTest.OpenInFrameWithDevToolsDoesNotCrash
--PictureInPictureWindowControllerBrowserTest.OpenSecondPictureInPictureStopsFirst
--PictureInPictureWindowControllerBrowserTest.PictureInPictureAfterClosingTab
--PictureInPictureWindowControllerBrowserTest.PlayPauseStateAtCreation
--PictureInPictureWindowControllerBrowserTest.PreloadNoneSrcChangeThenLoad
--PictureInPictureWindowControllerBrowserTest.RequestPictureInPictureAfterDisablePictureInPicture
--PictureInPictureWindowControllerBrowserTest.RequestPictureInPictureTwiceFromSameVideo
--PictureInPictureWindowControllerBrowserTest.ResetVideoSrcKeepsPictureInPictureWindowOpened
--PictureInPictureWindowControllerBrowserTest.ResizeEventFired
--PictureInPictureWindowControllerBrowserTest.TabIconUpdated
--PictureInPictureWindowControllerBrowserTest.UpdateVideoSrcKeepsPictureInPictureWindowOpened
-
-# Picture-in-Picture does not work with mash because VideoSurfaceLayer is
-# disabled. https://crbug.com/827327
--PlatformAppBrowserTest.PictureInPicture
-
-# Display rotation tests.
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.ConnectSecondDisplay/0
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.ConnectSecondDisplay/1
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.ConnectSecondDisplay/2
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.ConnectSecondDisplay/3
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.EnumsInSync/0
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.EnumsInSync/1
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.EnumsInSync/2
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.EnumsInSync/3
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.FirstDisplay/0
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.FirstDisplay/1
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.FirstDisplay/2
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.FirstDisplay/3
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.RefreshSecondDisplay/0
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.RefreshSecondDisplay/1
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.RefreshSecondDisplay/2
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.RefreshSecondDisplay/3
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.SetAndUnsetPolicy/0
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.SetAndUnsetPolicy/1
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.SetAndUnsetPolicy/2
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.SetAndUnsetPolicy/3
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.SetAndUnsetPolicyWithUserInteraction/0
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.SetAndUnsetPolicyWithUserInteraction/1
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.SetAndUnsetPolicyWithUserInteraction/2
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.SetAndUnsetPolicyWithUserInteraction/3
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.UserInteraction/0
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.UserInteraction/1
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.UserInteraction/2
--PolicyDisplayRotationDefault/DisplayRotationDefaultTest.UserInteraction/3
-
-# Full screen button tests.
--PresentationReceiverWindowViewBrowserTest.ChromeOSHardwareFullscreenButton
-
-# Omnibox tests.
--RoundedOmniboxPopupContentsViewTest.ClickOmnibox/Rounded
-
-# Service worker tests.
--ServiceWorkerTestWithJSBindings/ServiceWorkerTest.SWServedBackgroundPageReceivesEvent/0
-
-# App shelf tests.
--ShelfAppBrowserTest.AltNumberTabsTabbing
--ShelfAppBrowserTest.LaunchAppFromDisplayWithoutFocus0
--ShelfAppBrowserTest.LaunchAppFromDisplayWithoutFocus1
--ShelfAppBrowserTestNoDefaultBrowser.AltNumberBrowserTabbing
--ShelfAppBrowserTestNoDefaultBrowser.BrowserShortcutLauncherItemController
-
-# Shutdown policy tests.
--ShutdownPolicyLockerTest.PolicyChange
--ShutdownPolicyLockerTest.TestBasic
-
-# Sign-in extensions test.
--SigninExtensionsDeviceCloudPolicyBrowserTest.InstallAndRunInWindow
--SigninProfileAppsPolicyPerChannelTest.ExtensionInstallation/0
--SigninProfileAppsPolicyPerChannelTest.ExtensionInstallation/1
--SigninProfileAppsPolicyPerChannelTest.ExtensionInstallation/2
--SigninProfileAppsPolicyPerChannelTest.ExtensionInstallation/3
--SigninProfileAppsPolicyPerChannelTest.ExtensionInstallation/4
--SigninProfileAppsPolicyPerChannelTest.NotWhitelistedAppInstallation/0
--SigninProfileAppsPolicyPerChannelTest.NotWhitelistedAppInstallation/1
--SigninProfileAppsPolicyPerChannelTest.NotWhitelistedAppInstallation/2
--SigninProfileAppsPolicyPerChannelTest.NotWhitelistedAppInstallation/3
--SigninProfileAppsPolicyPerChannelTest.NotWhitelistedAppInstallation/4
--SigninProfileAppsPolicyPerChannelTest.WhitelistedAppInstallation/0
--SigninProfileAppsPolicyPerChannelTest.WhitelistedAppInstallation/1
--SigninProfileAppsPolicyPerChannelTest.WhitelistedAppInstallation/2
--SigninProfileAppsPolicyPerChannelTest.WhitelistedAppInstallation/3
--SigninProfileAppsPolicyPerChannelTest.WhitelistedAppInstallation/4
--SigninProfileAppsPolicyTest.BackgroundPage
--SigninProfileAppsPolicyTest.ExtensionsEnabled
--SigninProfileAppsPolicyTest.MultipleApps
-
-# Startup metrics tests.
--StartupMetricsTest.ReportsValues
-
-# Clock policy tests.
--SystemUse24HourClockPolicyTest.CheckFalse
--SystemUse24HourClockPolicyTest.CheckTrue
--SystemUse24HourClockPolicyTest.CheckUnset
-
-# Tab capture tests.
--TabCaptureApiPixelTest.EndToEndThroughWebRTC
--TabCaptureApiPixelTest.EndToEndWithoutRemoting
--TabCaptureApiPixelTest.OffscreenTabEndToEnd
--TabCaptureApiPixelTest.OffscreenTabEvilTests
+# The browser frame is a work in progress.
+-BrowserNonClientFrameViewAshTest.AvatarDisplayOnTeleportedWindow/*
+-BrowserNonClientFrameViewAshTest.HeaderHeightForSnappedBrowserInSplitView/*
+-BrowserNonClientFrameViewAshTest.ImmersiveModeTopViewInset/*
+-BrowserNonClientFrameViewAshTest.TopViewInset/*
 
 # Touch gestures don't work in webcontents. https://crbug.com/866991.
 -TopControlsSlideControllerTest.DisplayRotation
@@ -280,44 +38,174 @@
 -TopControlsSlideControllerTest.TestClosingATab
 -TopControlsSlideControllerTest.TestFocusEditableElements
 
-# Unmanaged platform keys tests.
--Unmanaged/UnmanagedPlatformKeysTest.Basic/0
--Unmanaged/UnmanagedPlatformKeysTest.Basic/1
--Unmanaged/UnmanagedPlatformKeysTest.Basic/2
--Unmanaged/UnmanagedPlatformKeysTest.Basic/3
--Unmanaged/UnmanagedPlatformKeysTest.Permissions/0
--Unmanaged/UnmanagedPlatformKeysTest.Permissions/1
--Unmanaged/UnmanagedPlatformKeysTest.Permissions/2
--Unmanaged/UnmanagedPlatformKeysTest.Permissions/3
+# Direct access to ash window frames, tablet mode, overview mode, etc.
+-NonHomeLauncherBrowserNonClientFrameViewAshTest.*
 
-# Flaky tests. crbug.com/880584
--UnifiedAutoplaySettingBrowserTest.Allow
--UnifiedAutoplaySettingBrowserTest.Block
+# Fix immersive fullscreen mode in mash. https://crbug.com/844748.
+# Needs EventGenerator to work across window tree hosts. crbug.com/814675
+-ImmersiveModeBrowserViewTest.TestCaptionButtonsReceiveEventsInAppImmersiveMode*
+-ImmersiveModeBrowserViewTest.TestCaptionButtonsReceiveEventsInBrowserImmersiveMode*
 
-# Virtual keyboard tests.
--VirtualKeyboardAppWindowTest.DisableOverscrollForImeWindow
--VirtualKeyboardStateTest.DisablingKeyboardGoesToInitialState
--VirtualKeyboardStateTest.OpenAndCloseAndOpen
--VirtualKeyboardStateTest.OpenTwice
--VirtualKeyboardStateTest.StateResolvesAfterPreload
--VirtualKeyboardWebContentTest.CanDragFloatingKeyboardWithMouse
--VirtualKeyboardWebContentTest.DoesNotCrashWhenParentDoesNotExist
--VirtualKeyboardWebContentTest.EnableIMEInDifferentExtension
+# Need pixel copy support. http://crbug.com/754864 http://crbug.com/754872
+-CastMirroringServiceHostBrowserTest.CaptureTabVideo
+-CastStreamingApiTestWithPixelOutput.*
+-TabCaptureApiPixelTest.*
+
+# RefCounted check failed: CalledOnValidSequence() from SchedulerWorkerDelegate::OnMainExit
+-CheckSystemTokenAvailability/EnterprisePlatformKeysTest.*
+
+# aura::CrashInFlightChange::ChangeFailed() when searching PDF.
+-ChromeFindRequestManagerTest.*
+-PDFExtensionTest.*
+-PDFExtensionHitTestTest.*
+
+# ash::Shell access for LogoutConfirmationController
+-DeviceLocalAccountTest.*
+
+# Fails: immersive_controller->IsRevealed() returns false.
+# http://crbug.com/791148
+-vZoomBubbleBrowserTest.*
+
+# ash::Shell::display_manager() to update displays.
+# http://crbug.com/831826
+-PolicyDisplayRotationDefault/DisplayRotationDefaultTest.*
+
+# JS failure: hasAccessToCurrentWindow: FAIL (no message)
+-LockScreenNoteTakingTest.*
+
+# desktop_window_tree_host_mus.cc(796) Check failed: !window->GetRootWindow() || this->window() == window->GetRootWindow().
+-LoginFeedbackTest.*
+
+# Missing magnification manager and also RefCounted check failed:
+# CalledOnValidSequence() from SchedulerWorkerDelegate::OnMainExit
+-LoginScreenDefaultPolicyLoginScreenBrowsertest.*
+
+# ash::Shell access in test for display configuration.
+# http://crbug.com/831826
+-ShelfAppBrowserTest.LaunchAppFromDisplayWithoutFocus*
+
+# Timeout.
+-StartupMetricsTest.*
+
+# Timeouts in content::WaitForChildFrameSurfaceReady()
+# Crashes in viz::HostFrameSinkManager::RegisterFrameSinkId()
+# http://crbug.com/755328
+-WebViewTest.*
+
+# Needs EventGenerator to work across window tree hosts. crbug.com/814675
+-RoundedOmniboxPopupContentsViewTest.ClickOmnibox*
+
+# RenderFrameMetadata observation not supported: https://crbug.com/820974
+-WebViewFocusBrowserPluginSpecificTest.*
+-WebViewScrollBubbling/WebViewGuestScrollTest.ScrollLatchingPreservedInGuests/*
+-WebViewScrollBubbling/WebViewGuestScrollTouchTest.*
+-WebViewScrollGuestContentBrowserPluginSpecificTest.OverscrollControllerSeesConsumedScrollsInGuest
+-WebViewScrollBubbling/WebViewGuestScrollTest.TestGuestWheelScrollsBubble/*
 
 # FATAL:hit_test_region_observer.cc(164)] Check failed: frame_sink_id.is_valid().
 -WebViewGuestTouchFocusBrowserPluginSpecificTest.TouchFocusesBrowserPluginInEmbedder
--WebViewScrollBubbling/WebViewGuestScrollTest.ScrollLatchingPreservedInGuests/0
--WebViewScrollBubbling/WebViewGuestScrollTest.ScrollLatchingPreservedInGuests/1
--WebViewScrollBubbling/WebViewGuestScrollTest.TestGuestWheelScrollsBubble/0
--WebViewScrollBubbling/WebViewGuestScrollTest.TestGuestWheelScrollsBubble/1
--WebViewScrollBubbling/WebViewGuestScrollTouchTest.TestGuestGestureScrollsBubble/0
--WebViewScrollBubbling/WebViewGuestScrollTouchTest.TestGuestGestureScrollsBubble/1
--WebViewScrollGuestContentBrowserPluginSpecificTest.OverscrollControllerSeesConsumedScrollsInGuest
--WebViewTest.InterstitialPageFocusedWidget
--WebViewTest.InterstitialPageRouteEvents
--WebViewTest.ReloadAfterCrash
 
-# Window Open API tests.
+# Picture-in-Picture does not work with mash because VideoSurfaceLayer is
+# disabled.
+# https://crbug.com/827327
+-PictureInPictureWindowControllerBrowserTest.*
+-ControlPictureInPictureWindowControllerBrowserTest.*
+-BrowserActionApiTest.TestPictureInPictureOnBrowserActionIconClick
+-PlatformAppBrowserTest.PictureInPicture
+-PictureInPictureLazyBackgroundPageApiTest.PictureInPictureInBackgroundPage
+
+# These started failing with the switch to ws2.
+# https:://crbug.com/855767
+-AppWindowApiTest.OnRestoredEvent
+-BrowserActionApiTest.BrowserActionPopupWithIframe
+-FirstRunUIBrowserTest.ModalWindowDoesNotBlock
+-LauncherPlatformAppBrowserTest.AltNumberAppsTabbing
+-LauncherPlatformAppBrowserTest.PackagedAppClickBehaviorInMinimizeMode
+-LoginWebDialogTest.CannotMinimize
+-LoginWebDialogTest.CloseDialogByAccelerator
+-ShelfAppBrowserTest.AltNumberTabsTabbing
+-ShelfAppBrowserTestNoDefaultBrowser.AltNumberBrowserTabbing
+-ShelfAppBrowserTestNoDefaultBrowser.BrowserShortcutLauncherItemController
+
+# Excluded from Mash because pointer events from EventGenerator aren't seen.
+# https://crbug.com/814675
+-ChromeOSInfoPrivateTest.StylusSeen
+
+# --------------------------------------------------
+# Tests failing only for SingleProcessMash.
+# --------------------------------------------------
+
+# Uses ash::WindowState in browser process.
+-AcceleratorCommandsBrowserTest.ToggleMaximized
+
+# Crashes on exit, even without SingleProcessMash.
+-AffiliationCheck/EnterpriseDeviceAttributesTest.Success/*
+
+# Flaky tests. crbug.com/880584
+-AutoplayMetricsBrowserTest.RecordAutoplayAttemptUkm
+
+# Blub Arc tests.
+-Blub/UnaffiliatedArcAllowedTest.ProfileTest/0
+-Blub/UnaffiliatedArcAllowedTest.ProfileTest/1
+
+# Browser command controller tests.
+-BrowserCommandControllerBrowserTest.LockedFullscreen
+
+# Enterprise keys tests.
+-CheckSystemTokenAvailability/EnterprisePlatformKeysTest.Basic/*
+
+# Ash native views tests.
+-ChromeNativeAppWindowViewsAuraAshBrowserTest.*
+
+# Context menu tests.
+-ContextMenuBrowserTest.ContextMenuEntriesAreDisabledInLockedFullscreen
+
+# Default extension tests.
+-DefaultProfileExtensionBrowserTest.NoExtensionHosts
+
+# Immersive mode tests.
+-ImmersiveModeBrowserViewTest.TabNavigationAcceleratorsFullscreenBrowser/material
+
+# Lock screen tests.
+-LockScreenNoteTakingTest.Launch
+
+# Login screen tests.
+-LoginScreenPolicyTest.DisableSupervisedUsers
+
+# PRE steps crash on shutdown.
+# FATAL:ref_counted.h(85)] Check failed: CalledOnValidSequence()
+-ManagedWithoutPermission/ManagedWithoutPermissionPlatformKeysTest.*
+-ManagedWithPermission/ManagedWithPermissionPlatformKeysTest.*
+
+# Flaky tests. crbug.com/880584
+-MSE_ClearKey/EncryptedMediaTest.Playback_Multiple_VideoAudio_WebM/*
+-MSE_ExternalClearKey/EncryptedMediaTest.Playback_Multiple_VideoAudio_WebM/*
+
+# Full screen button tests.
+-PresentationReceiverWindowViewBrowserTest.ChromeOSHardwareFullscreenButton
+
+# Service worker tests.
+-ServiceWorkerTestWithJSBindings/ServiceWorkerTest.SWServedBackgroundPageReceivesEvent/*
+
+# Shutdown policy tests.
+-ShutdownPolicyLockerTest.PolicyChange
+-ShutdownPolicyLockerTest.TestBasic
+
+# Sign-in extensions test.
+-SigninExtensionsDeviceCloudPolicyBrowserTest.InstallAndRunInWindow
+-SigninProfileAppsPolicyPerChannelTest.*
+-SigninProfileAppsPolicyTest.*
+
+# Clock policy tests.
+-SystemUse24HourClockPolicyTest.*
+
+# Unmanaged platform keys tests.
+-Unmanaged/UnmanagedPlatformKeysTest.*
+
+# Flaky tests. crbug.com/880584
+-UnifiedAutoplaySettingBrowserTest.*
+
+# Window Open API tests.  https://crbug.com/815379
 -WindowOpenApiTest.OpenLockedFullscreenWindow
 -WindowOpenApiTest.RemoveLockedFullscreenFromWindow
 -WindowOpenApiTest.RemoveLockedFullscreenFromWindowWithoutPermission
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
index 143d3ee..60ae0771 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-blink-features=LayoutNG
@@ -439,11 +439,6 @@
 crbug.com/591099 http/tests/devtools/network/network-datareceived.js [ Failure ]
 crbug.com/591099 http/tests/devtools/network/network-datasaver-warning.js [ Failure ]
 crbug.com/591099 http/tests/devtools/persistence/persistence-merge-editor-tabs.js [ Failure ]
-crbug.com/591099 http/tests/devtools/tracing/timeline-misc/timeline-grouped-invalidations.js [ Failure ]
-crbug.com/591099 http/tests/devtools/tracing/timeline-paint/timeline-paint-and-multiple-style-invalidations.js [ Failure ]
-crbug.com/591099 http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations-on-deleted-node.js [ Timeout ]
-crbug.com/591099 http/tests/devtools/tracing/timeline-paint/timeline-paint-with-layout-invalidations.js [ Failure ]
-crbug.com/591099 http/tests/devtools/tracing/timeline-paint/timeline-paint-with-style-recalc-invalidations.js [ Failure ]
 crbug.com/591099 http/tests/images/restyle-decode-error.html [ Failure ]
 crbug.com/591099 http/tests/local/fileapi/select-dragged-file-input.html [ Skip ]
 crbug.com/591099 http/tests/misc/object-embedding-svg-delayed-size-negotiation.xhtml [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
index 1bd27b57..1eba2f8 100644
--- a/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
+++ b/third_party/WebKit/LayoutTests/FlagExpectations/enable-features=NetworkService
@@ -31,4 +31,3 @@
 crbug.com/715632 external/wpt/fetch/sec-metadata/sharedworker.tentative.https.sub.html [ Failure ]
 crbug.com/715632 fast/workers/shared-worker-load-error.html [ Timeout ]
 crbug.com/715632 http/tests/fetch/chromium/data-saver.html [ Failure ]
-crbug.com/715632 fast/workers/chromium/worker-crash-with-invalid-location.html [ Crash ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 44aaa8d9..095fa77 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -38,7 +38,7 @@
 #  transforms
 # Some additional bugs that are caused by painting problems are also within this section.
 
-crbug.com/805292 hittesting/image-with-clip-path.html [ Skip ]
+crbug.com/805292 hittesting/image-with-clip-path.html [ Pass Failure Crash ]
 
 # Failures due to SPV2, that don't also fail without SPV2. DO NOT REBASELINE.
 # SPv2 paint properties are still being implemented.
@@ -1603,6 +1603,7 @@
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/percentage-heights-002.html [ Skip ]
 crbug.com/467127 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/percentage-heights-003.html [ Skip ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/percentage-heights-004.html [ Skip ]
+crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/percentage-heights-quirks-node.html [ Skip ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/percentage-size-subitems-001.html [ Skip ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/percentage-widths-001.html [ Skip ]
 crbug.com/591099 virtual/layout_ng_experimental/external/wpt/css/css-flexbox/position-absolute-001.html [ Skip ]
@@ -2262,6 +2263,10 @@
 crbug.com/806357 [ Win Debug ] virtual/threaded/fast/events/pointerevents/pinch/pointerevent_touch-action-pinch_zoom_touch.html [ Pass Failure ]
 crbug.com/839038 [ Mac ] external/wpt/pointerevents/pointerevent_lostpointercapture_for_disconnected_node-manual.html [ Skip ]
 
+crbug.com/346473  fast/events/drag-on-mouse-move-cancelled.html [ Failure ]
+crbug.com/346473  virtual/mouseevent_fractional/fast/events/drag-on-mouse-move-cancelled.html [ Failure ]
+crbug.com/346473  virtual/user-activation-v2/fast/events/drag-on-mouse-move-cancelled.html [ Failure ]
+
 # These tests are skipped as there is no touch support on Mac.
 crbug.com/613672 [ Mac ] external/wpt/feature-policy/experimental-features/vertical-scroll-touch-block-manual.tentative.html [ Skip ]
 crbug.com/613672 [ Mac ] virtual/video-surface-layer/external/wpt/feature-policy/experimental-features/vertical-scroll-touch-block-manual.tentative.html [ Skip ]
@@ -2762,8 +2767,10 @@
 crbug.com/875249 external/wpt/infrastructure/testdriver/bless.html [ Timeout Pass ]
 
 # ====== New tests from wpt-importer added here ======
-crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-path-002.html [ Failure ]
-crbug.com/626703 external/wpt/css/css-masking/clip-path/clip-path-path-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-contain/contain-size-multicol-001.html [ Failure ]
+crbug.com/626703 external/wpt/css/css-contain/contain-size-grid-002.html [ Failure ]
+crbug.com/880983 external/wpt/css/css-masking/clip-path/clip-path-path-002.html [ Failure ]
+crbug.com/880983 external/wpt/css/css-masking/clip-path/clip-path-path-001.html [ Failure ]
 crbug.com/432153 external/wpt/css/css-masking/mask-image/mask-image-url-local-mask.html [ Failure ]
 crbug.com/432153 external/wpt/css/css-masking/mask-image/mask-image-url-image.html [ Failure ]
 crbug.com/432153 external/wpt/css/css-masking/mask-image/mask-image-url-remote-mask.html [ Failure ]
@@ -3933,9 +3940,6 @@
 
 crbug.com/689781 external/wpt/media-source/mediasource-duration.html [ Failure Pass ]
 
-crbug.com/860637 http/tests/wasm_streaming/regression860637.html [ Skip ]
-crbug.com/860637 virtual/enable_wasm_streaming/http/tests/wasm_streaming/regression860637.html [ Skip ]
-
 crbug.com/681468 fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom125.html [ Failure Pass ]
 crbug.com/681468 fast/forms/suggestion-picker/date-suggestion-picker-appearance-zoom200.html [ Failure Pass ]
 crbug.com/681468 [ Win ] virtual/scalefactor150/fast/hidpi/static/data-suggestion-picker-appearance.html [ Failure Pass Timeout ]
diff --git a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
index a9b64cb..9e8ae291 100644
--- a/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
+++ b/third_party/WebKit/LayoutTests/external/WPT_BASE_MANIFEST_5.json
@@ -14221,6 +14221,18 @@
      {}
     ]
    ],
+   "css/CSS2/normal-flow/float-percentage-resolution-quirks-mode.html": [
+    [
+     "/css/CSS2/normal-flow/float-percentage-resolution-quirks-mode.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square-only.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/CSS2/normal-flow/height-001.xht": [
     [
      "/css/CSS2/normal-flow/height-001.xht",
@@ -35981,6 +35993,18 @@
      {}
     ]
    ],
+   "css/css-contain/contain-layout-018.html": [
+    [
+     "/css/css-contain/contain-layout-018.html",
+     [
+      [
+       "/css/reference/nothing.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-contain/contain-layout-breaks-001.html": [
     [
      "/css/css-contain/contain-layout-breaks-001.html",
@@ -36425,6 +36449,18 @@
      {}
     ]
    ],
+   "css/css-contain/contain-paint-025.html": [
+    [
+     "/css/css-contain/contain-paint-025.html",
+     [
+      [
+       "/css/reference/nothing.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-contain/contain-paint-047.html": [
     [
      "/css/css-contain/contain-paint-047.html",
@@ -36965,6 +37001,18 @@
      {}
     ]
    ],
+   "css/css-contain/contain-size-grid-002.html": [
+    [
+     "/css/css-contain/contain-size-grid-002.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-contain/contain-size-monolithic-001.html": [
     [
      "/css/css-contain/contain-size-monolithic-001.html",
@@ -36977,6 +37025,18 @@
      {}
     ]
    ],
+   "css/css-contain/contain-size-multicol-001.html": [
+    [
+     "/css/css-contain/contain-size-multicol-001.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square.xht",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-contain/contain-size-scrollbars-001.html": [
     [
      "/css/css-contain/contain-size-scrollbars-001.html",
@@ -42329,6 +42389,18 @@
      {}
     ]
    ],
+   "css/css-flexbox/percentage-heights-quirks-node.html": [
+    [
+     "/css/css-flexbox/percentage-heights-quirks-node.html",
+     [
+      [
+       "/css/reference/ref-filled-green-100px-square-only.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-flexbox/percentage-size-subitems-001.html": [
     [
      "/css/css-flexbox/percentage-size-subitems-001.html",
@@ -81689,6 +81761,30 @@
      {}
     ]
    ],
+   "css/css-writing-modes/img-intrinsic-size-contribution-001.html": [
+    [
+     "/css/css-writing-modes/img-intrinsic-size-contribution-001.html",
+     [
+      [
+       "/css/css-writing-modes/img-intrinsic-size-contribution-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
+   "css/css-writing-modes/img-intrinsic-size-contribution-002.html": [
+    [
+     "/css/css-writing-modes/img-intrinsic-size-contribution-002.html",
+     [
+      [
+       "/css/css-writing-modes/img-intrinsic-size-contribution-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "css/css-writing-modes/inline-block-alignment-002.xht": [
     [
      "/css/css-writing-modes/inline-block-alignment-002.xht",
@@ -96701,6 +96797,18 @@
      {}
     ]
    ],
+   "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-auto-margins.html": [
+    [
+     "/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-auto-margins.html",
+     [
+      [
+       "/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-auto-margins-ref.html",
+       "=="
+      ]
+     ],
+     {}
+    ]
+   ],
    "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-none-rendering.html": [
     [
      "/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-none-rendering.html",
@@ -117756,11 +117864,6 @@
      {}
     ]
    ],
-   "css/css-contain/support/60x60-red.png": [
-    [
-     {}
-    ]
-   ],
    "css/css-contain/support/blue-100x100.png": [
     [
      {}
@@ -138276,6 +138379,11 @@
      {}
     ]
    ],
+   "css/css-writing-modes/img-intrinsic-size-contribution-ref.html": [
+    [
+     {}
+    ]
+   ],
    "css/css-writing-modes/inline-block-alignment-002-ref.xht": [
     [
      {}
@@ -139726,6 +139834,11 @@
      {}
     ]
    ],
+   "css/css-writing-modes/support/blue-200x100.png": [
+    [
+     {}
+    ]
+   ],
    "css/css-writing-modes/support/blue-horiz-line-220x1.png": [
     [
      {}
@@ -157071,6 +157184,11 @@
      {}
     ]
    ],
+   "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-auto-margins-ref.html": [
+    [
+     {}
+    ]
+   ],
    "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-display-expected.txt": [
     [
      {}
@@ -175626,11 +175744,6 @@
      {}
     ]
    ],
-   "webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "webaudio/the-audio-api/the-audioparam-interface/automation-rate-testing.js": [
     [
      {}
@@ -175771,11 +175884,6 @@
      {}
     ]
    ],
-   "webaudio/the-audio-api/the-pannernode-interface/ctor-panner-expected.txt": [
-    [
-     {}
-    ]
-   ],
    "webaudio/the-audio-api/the-periodicwave-interface/.gitkeep": [
     [
      {}
@@ -197923,6 +198031,12 @@
      {}
     ]
    ],
+   "css/css-position/position-sticky-overflow-hidden.html": [
+    [
+     "/css/css-position/position-sticky-overflow-hidden.html",
+     {}
+    ]
+   ],
    "css/css-position/position-sticky-overflow-padding.html": [
     [
      "/css/css-position/position-sticky-overflow-padding.html",
@@ -291121,11 +291235,11 @@
    "testharness"
   ],
   "cookies/prefix/__host.header.html": [
-   "5a522cbaa018aa607628070ab79278dd855735bd",
+   "de46485e44c1d349143a9ec7681aea82d1561ee2",
    "testharness"
   ],
   "cookies/prefix/__host.header.https.html": [
-   "53d0dba65989164f5fcb77becd021f264822ebf7",
+   "a71f75ef41bbcda09ed1dd4a6c666cb51f876fdd",
    "testharness"
   ],
   "cookies/prefix/__secure.document-cookie.html": [
@@ -291137,11 +291251,11 @@
    "testharness"
   ],
   "cookies/prefix/__secure.header.html": [
-   "431e0e1ec98923feae1f1f6948c7728e5e80b007",
+   "fb369b62a3bb2e5526a28351813af162a31b4323",
    "testharness"
   ],
   "cookies/prefix/__secure.header.https.html": [
-   "d912babc239acfecef7afb6f7deac9fbfeaf50bd",
+   "8753a320b4e5925bc2acb88861ee24c4cebe79af",
    "testharness"
   ],
   "cookies/prefix/document-cookie.non-secure.html": [
@@ -291149,7 +291263,7 @@
    "testharness"
   ],
   "cookies/resources/cookie-helper.sub.js": [
-   "d00a11f6f4396177a9885e30adac435fe8dab479",
+   "2974da9af069d0fa82779c7c250eb467283f558a",
    "support"
   ],
   "cookies/resources/drop.py": [
@@ -291197,7 +291311,7 @@
    "support"
   ],
   "cookies/resources/set.py": [
-   "abfb8c8d40d2466759bb423bc8e7fdfc5d72b1fb",
+   "5b6d0b9a2cc4d233d101441bb10f47418da9b63d",
    "support"
   ],
   "cookies/resources/setSameSite.py": [
@@ -291245,7 +291359,7 @@
    "testharness"
   ],
   "cookies/samesite/window-open-reload.html": [
-   "b37cff8286a17b14f8a07c4786a100cce7bb05b6",
+   "fd9c7a6d5a8c2ca8ac184dadf72b8d397e8af8cb",
    "testharness"
   ],
   "cookies/samesite/window-open.html": [
@@ -296488,6 +296602,10 @@
    "b3a7420c630ad4c84e5593ad48f48f3072a88b98",
    "visual"
   ],
+  "css/CSS2/normal-flow/float-percentage-resolution-quirks-mode.html": [
+   "a3794579f0ea242f9e7faaffcc16de5a3a69cf7c",
+   "reftest"
+  ],
   "css/CSS2/normal-flow/height-001-ref.xht": [
    "6d9a9e39bad87e33d33252aae31e85cb5b47f877",
    "support"
@@ -311076,6 +311194,10 @@
    "c8118ad974844cd807e0dfbcc07a9a06469a308c",
    "reftest"
   ],
+  "css/css-contain/contain-layout-018.html": [
+   "5d7ebc0195cbbb7bc303784ab05296885c323f40",
+   "reftest"
+  ],
   "css/css-contain/contain-layout-breaks-001.html": [
    "a85cf2c6c8e00f1d21fa5a63da81eff8148f3d71",
    "reftest"
@@ -311224,6 +311346,10 @@
    "79ef8a7cc0841ab96b1650cb2e78d210a9432180",
    "reftest"
   ],
+  "css/css-contain/contain-paint-025.html": [
+   "0a41b62b2c169d2a5e571bde059a78ad2d5c2a16",
+   "reftest"
+  ],
   "css/css-contain/contain-paint-047.html": [
    "e4a0b28457c752232f4314175ffdf1840f7e336a",
    "reftest"
@@ -311404,10 +311530,18 @@
    "f67f0e118e00b3426986b39226310c59b14a3755",
    "reftest"
   ],
+  "css/css-contain/contain-size-grid-002.html": [
+   "1e7771e7c12b9c5c879e52071f9f566bd6e2b7d7",
+   "reftest"
+  ],
   "css/css-contain/contain-size-monolithic-001.html": [
    "30f19b6cbbd6f6737d5175b1946c17805e0568d6",
    "reftest"
   ],
+  "css/css-contain/contain-size-multicol-001.html": [
+   "5c0dba9b7bb56792542decc9abd8fcebd8ab967a",
+   "reftest"
+  ],
   "css/css-contain/contain-size-scrollbars-001.html": [
    "304e81e5c98c0ded48c9c498e451dd6c0041566b",
    "reftest"
@@ -311664,10 +311798,6 @@
    "a5b4e9f47a8e60ad0bede1ac81e02b3542c80f3b",
    "support"
   ],
-  "css/css-contain/support/60x60-red.png": [
-   "823f125b8e4a60f780f00443c9c9a10b9fa1f447",
-   "support"
-  ],
   "css/css-contain/support/blue-100x100.png": [
    "3b72d5ce53c07b68fe508bb57aa61a933dbda768",
    "support"
@@ -314900,6 +315030,10 @@
    "4f162487a711c78f48bf457d3fb0764bb5f2b746",
    "reftest"
   ],
+  "css/css-flexbox/percentage-heights-quirks-node.html": [
+   "4b254b46467d6abff049090d5f37b1f3b3f6178e",
+   "reftest"
+  ],
   "css/css-flexbox/percentage-size-subitems-001.html": [
    "70f3953052a3a770c6cd15ee169607a00fc452b0",
    "reftest"
@@ -329192,6 +329326,10 @@
    "ade9e108cf45039173066cedec39462fa37e5d95",
    "testharness"
   ],
+  "css/css-position/position-sticky-overflow-hidden.html": [
+   "b1dc49f34fe0cd5386e41acedc179e9d1af90ecb",
+   "testharness"
+  ],
   "css/css-position/position-sticky-overflow-padding.html": [
    "fab6f2f731a5ac4acf13fff10b3d47470e7a7d05",
    "testharness"
@@ -350216,6 +350354,18 @@
    "d33fb6f6d119443f41217c2ac1b808cb3eb79b7f",
    "reftest"
   ],
+  "css/css-writing-modes/img-intrinsic-size-contribution-001.html": [
+   "08500537f87cdccc1e0736bbaea483b61b690630",
+   "reftest"
+  ],
+  "css/css-writing-modes/img-intrinsic-size-contribution-002.html": [
+   "df0ccf2093bf878200e719cc4f66c70d9832a8a0",
+   "reftest"
+  ],
+  "css/css-writing-modes/img-intrinsic-size-contribution-ref.html": [
+   "ffda7d62ba963ed693e14547adce6592a11f5657",
+   "support"
+  ],
   "css/css-writing-modes/inline-block-alignment-002-ref.xht": [
    "ce478e7499247e6277482b9c16c9dd2b1b76f275",
    "support"
@@ -352500,6 +352650,10 @@
    "d325b15a4cf3f12e54adf85c3691de11bebac057",
    "support"
   ],
+  "css/css-writing-modes/support/blue-200x100.png": [
+   "e32c47dd1ee8f250025b930a78ce076889af942d",
+   "support"
+  ],
   "css/css-writing-modes/support/blue-horiz-line-220x1.png": [
    "3898d5a2d9eb14ad80343ecbcd9d8216d2e2f755",
    "support"
@@ -379404,6 +379558,14 @@
    "f7511c9e4c91dbd2cb11db502789d8792f038a29",
    "testharness"
   ],
+  "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-auto-margins-ref.html": [
+   "8b1258727fce344978609a1b033389edce7b20be",
+   "support"
+  ],
+  "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-auto-margins.html": [
+   "dd1964ba25133850b764c29037fb1113a7c6736f",
+   "reftest"
+  ],
   "html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-block-formatting-context.html": [
    "4e9539179739a3690aab276f2ba98c25bd4dfe9b",
    "testharness"
@@ -402061,7 +402223,7 @@
    "testharness"
   ],
   "payment-request/payment-response/onpayerdetailchange-attribute.manual.https.html": [
-   "9f92d284063fcec7c0ffefb09a076a285cd4b766",
+   "c8dd92636c6392b2436c8235340355c4529e12c1",
    "testharness"
   ],
   "payment-request/payment-response/payerEmail-attribute-manual.https.html": [
@@ -421596,12 +421758,8 @@
    "ab2edfd009f1320fdb8e0a49dffb984baed36f05",
    "testharness"
   ],
-  "webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions-expected.txt": [
-   "4c36f417d222212f46d0dfaf96c0d57f7656d9b3",
-   "support"
-  ],
   "webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurve-exceptions.html": [
-   "98f64a0379c5eda5d0ba03226fb89f1cedb4fba8",
+   "37062993f9dc8d90e2d418c842b30e20517bd21d",
    "testharness"
   ],
   "webaudio/the-audio-api/the-audioparam-interface/audioparam-setValueCurveAtTime.html": [
@@ -422096,12 +422254,8 @@
    "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391",
    "support"
   ],
-  "webaudio/the-audio-api/the-pannernode-interface/ctor-panner-expected.txt": [
-   "6a65dca34430a72c2b6d06d4d95819caf4350d27",
-   "support"
-  ],
   "webaudio/the-audio-api/the-pannernode-interface/ctor-panner.html": [
-   "cdad5977c70251edc0e8ecfac68c42cc4d2c7e41",
+   "d330c9c3de4482ee70c036e0ab7ff8feb1fd5a36",
    "testharness"
   ],
   "webaudio/the-audio-api/the-pannernode-interface/distance-exponential.html": [
@@ -422141,7 +422295,7 @@
    "testharness"
   ],
   "webaudio/the-audio-api/the-pannernode-interface/panner-rolloff-clamping.html": [
-   "e1519f8c3027b3e38004e54ba6088ae819bedff1",
+   "387f87301092ebd725ed240cc70f0df7ec69a5ab",
    "testharness"
   ],
   "webaudio/the-audio-api/the-pannernode-interface/pannernode-basic.html": [
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookies/prefix/__host.header.html b/third_party/WebKit/LayoutTests/external/wpt/cookies/prefix/__host.header.html
index 5a522cb..de46485e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/cookies/prefix/__host.header.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/cookies/prefix/__host.header.html
@@ -8,6 +8,7 @@
     set_prefixed_cookie_via_http_test({
       prefix: "__Host-",
       params: "Path=/;" + extraParams,
+      origin: self.origin,
       shouldExistInDOM: false,
       shouldExistViaHTTP: false,
       title: "__Host: Non-secure origin: Does not set 'Path=/;" + extraParams + "'"
@@ -17,6 +18,7 @@
     set_prefixed_cookie_via_http_test({
       prefix: "__Host-",
       params: "Secure; Path=/;" + extraParams,
+      origin: self.origin,
       shouldExistInDOM: false,
       shouldExistViaHTTP: false,
       title: "__Host: Non-secure origin: Does not set 'Secure; Path=/;" + extraParams + "'"
@@ -26,6 +28,7 @@
     set_prefixed_cookie_via_http_test({
       prefix: "__Host-",
       params: "Secure; Path=/; Domain=" + document.location.hostname + "; " + extraParams,
+      origin: self.origin,
       shouldExistInDOM: false,
       shouldExistViaHTTP: false,
       title: "__Host: Secure origin: Does not set 'Secure; Path=/; Domain=" + document.location.hostname + "; " + extraParams + "'"
@@ -35,6 +38,7 @@
   set_prefixed_cookie_via_http_test({
     prefix: "__Host-",
     params: "Secure; Path=/cookies/resources/list.py",
+    origin: self.origin,
     shouldExistInDOM: false,
     shouldExistViaHTTP: false,
     title: "__Host: Non-secure origin: Does not set 'Secure; Path=/cookies/resources/list.py'"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookies/prefix/__host.header.https.html b/third_party/WebKit/LayoutTests/external/wpt/cookies/prefix/__host.header.https.html
index 53d0dba6..a71f75e 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/cookies/prefix/__host.header.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/cookies/prefix/__host.header.https.html
@@ -8,6 +8,7 @@
     set_prefixed_cookie_via_http_test({
       prefix: "__Host-",
       params: "Path=/;" + extraParams,
+      origin: self.origin,
       shouldExistInDOM: false,
       shouldExistViaHTTP: false,
       title: "__Host: Secure origin: Does not set 'Path=/;" + extraParams + "'"
@@ -17,6 +18,7 @@
     set_prefixed_cookie_via_http_test({
       prefix: "__Host-",
       params: "Secure; Path=/;" + extraParams,
+      origin: self.origin,
       shouldExistInDOM: true,
       shouldExistViaHTTP: true,
       title: "__Host: Secure origin: Does set 'Secure; Path=/;" + extraParams + "'"
@@ -26,6 +28,7 @@
     set_prefixed_cookie_via_http_test({
       prefix: "__Host-",
       params: "Secure; Path=/; Domain=" + document.location.hostname + "; " + extraParams,
+      origin: self.origin,
       shouldExistInDOM: false,
       shouldExistViaHTTP: false,
       title: "__Host: Secure origin: Does not set 'Secure; Path=/; Domain=" + document.location.hostname + "; " + extraParams + "'"
@@ -35,6 +38,7 @@
   set_prefixed_cookie_via_http_test({
     prefix: "__Host-",
     params: "Secure; Path=/cookies/resources/list.py",
+    origin: self.origin,
     shouldExistInDOM: false,
     shouldExistViaHTTP: false,
     title: "__Host: Secure origin: Does not set 'Secure; Path=/cookies/resources/list.py'"
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookies/prefix/__secure.header.html b/third_party/WebKit/LayoutTests/external/wpt/cookies/prefix/__secure.header.html
index 431e0e1e..fb369b62 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/cookies/prefix/__secure.header.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/cookies/prefix/__secure.header.html
@@ -8,6 +8,7 @@
     set_prefixed_cookie_via_http_test({
       prefix: "__Secure-",
       params: "Path=/;" + extraParams,
+      origin: self.origin,
       shouldExistViaHTTP: false,
       title: "__Secure: Non-secure origin: Should not set 'Path=/;" + extraParams + "'"
     });
@@ -16,8 +17,9 @@
     set_prefixed_cookie_via_http_test({
       prefix: "__Secure-",
       params: "Secure; Path=/;" + extraParams,
-      shouldExistViaHTTP: true,
-      title: "__Secure: Non-secure origin: Should set 'Secure; Path=/;" + extraParams + "'"
+      origin: self.origin,
+      shouldExistViaHTTP: false,
+      title: "__Secure: Non-secure origin: Should not set 'Secure; Path=/;" + extraParams + "'"
     });
   });
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookies/prefix/__secure.header.https.html b/third_party/WebKit/LayoutTests/external/wpt/cookies/prefix/__secure.header.https.html
index d912babc..8753a32 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/cookies/prefix/__secure.header.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/cookies/prefix/__secure.header.https.html
@@ -3,11 +3,12 @@
 <script src="/resources/testharnessreport.js"></script>
 <script src="/cookies/resources/cookie-helper.sub.js"></script>
 <script>
-  ["", "domain="+CROSS_SITE_HOST, "MaxAge=10", "HttpOnly"].forEach(extraParams => {
+  ["", "MaxAge=10", "HttpOnly"].forEach(extraParams => {
     // Without 'secure'
     set_prefixed_cookie_via_http_test({
       prefix: "__Secure-",
       params: "Path=/;" + extraParams,
+      origin: self.origin,
       shouldExistViaHTTP: false,
       title: "__Secure: secure origin: Should not set 'Path=/;" + extraParams + "'"
     });
@@ -16,8 +17,27 @@
     set_prefixed_cookie_via_http_test({
       prefix: "__Secure-",
       params: "Secure;Path=/;" + extraParams,
+      origin: self.origin,
       shouldExistViaHTTP: true,
       title: "__Secure: secure origin: Should set 'Secure;Path=/;" + extraParams + "'"
     });
   });
+
+  // Without 'secure'
+  set_prefixed_cookie_via_http_test({
+    prefix: "__Secure-",
+    params: "Path=/;domain=" + CROSS_SITE_HOST,
+    origin: SECURE_CROSS_SITE_ORIGIN,
+    shouldExistViaHTTP: false,
+    title: "__Secure: secure origin: Should not set 'Path=/;domain=" + CROSS_SITE_HOST + "'"
+  });
+
+  // With 'secure'
+  set_prefixed_cookie_via_http_test({
+    prefix: "__Secure-",
+    params: "Secure;Path=/;domain=" + CROSS_SITE_HOST,
+    origin: SECURE_CROSS_SITE_ORIGIN,
+    shouldExistViaHTTP: true,
+    title: "__Secure: secure origin: Should set 'Secure;Path=/;domain=" + CROSS_SITE_HOST + "'"
+  });
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookies/resources/cookie-helper.sub.js b/third_party/WebKit/LayoutTests/external/wpt/cookies/resources/cookie-helper.sub.js
index d00a11f..2974da9 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/cookies/resources/cookie-helper.sub.js
+++ b/third_party/WebKit/LayoutTests/external/wpt/cookies/resources/cookie-helper.sub.js
@@ -28,7 +28,13 @@
 
 // A tiny helper which returns the result of fetching |url| with credentials.
 function credFetch(url) {
-  return fetch(url, {"credentials": "include"});
+  return fetch(url, {"credentials": "include"})
+    .then(response => {
+      if (response.status !== 200) {
+        throw new Error(response.statusText);
+      }
+      return response;
+    });
 }
 
 // Returns a URL on |origin| which redirects to a given absolute URL.
@@ -87,23 +93,20 @@
 
 function set_prefixed_cookie_via_http_test(options) {
   promise_test(t => {
-    var postDelete = _ => {
-      var value = "" + Math.random();
-      return credFetch(options.origin + "/cookies/resources/set.py?" + name + "=" + value + ";" + options.params)
-        .then(_ => credFetch(options.origin + "/cookies/resources/list.py"))
-        .then(r => r.json())
-        .then(cookies => assert_equals(cookies[name], options.shouldExistViaHTTP ? value : undefined));
-    };
-
     var name = options.prefix + "prefixtestcookie";
-    if (!options.origin) {
-      options.origin = self.origin;
-      erase_cookie_from_js(name, options.params);
-      return postDelete;
-    } else {
-      return credFetch(options.origin + "/cookies/resources/drop.py?name=" + name)
-        .then(_ => postDelete());
-    }
+    var value = "" + Math.random();
+
+    t.add_cleanup(() => {
+      var cookie = name + "=0;expires=" + new Date(0).toUTCString() + ";" +
+        options.params;
+
+      return credFetch(options.origin + "/cookies/resources/set.py?" + cookie);
+    });
+
+    return credFetch(options.origin + "/cookies/resources/set.py?" + name + "=" + value + ";" + options.params)
+      .then(_ => credFetch(options.origin + "/cookies/resources/list.py"))
+      .then(r => r.json())
+      .then(cookies => assert_equals(cookies[name], options.shouldExistViaHTTP ? value : undefined));
   }, options.title);
 }
 
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookies/resources/set.py b/third_party/WebKit/LayoutTests/external/wpt/cookies/resources/set.py
index abfb8c8d..5b6d0b9a 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/cookies/resources/set.py
+++ b/third_party/WebKit/LayoutTests/external/wpt/cookies/resources/set.py
@@ -1,7 +1,13 @@
 import helpers
+import urllib
 
 def main(request, response):
     """Respond to `/cookie/set?{cookie}` by echoing `{cookie}` as a `Set-Cookie` header."""
     headers = helpers.setNoCacheAndCORSHeaders(request, response)
-    headers.append(("Set-Cookie", request.url_parts.query))
+
+    # Cookies may require whitespace (e.g. in the `Expires` attribute), so the
+    # query string should be decoded.
+    cookie = urllib.unquote(request.url_parts.query)
+    headers.append(("Set-Cookie", cookie))
+
     return headers, '{"success": true}'
diff --git a/third_party/WebKit/LayoutTests/external/wpt/cookies/samesite/window-open-reload.html b/third_party/WebKit/LayoutTests/external/wpt/cookies/samesite/window-open-reload.html
index b37cff8..fd9c7a6 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/cookies/samesite/window-open-reload.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/cookies/samesite/window-open-reload.html
@@ -40,5 +40,5 @@
 
   create_test(ORIGIN, ORIGIN, SameSiteStatus.STRICT, "Reloaded same-host auxiliary navigations are strictly same-site.");
   create_test(SUBDOMAIN_ORIGIN, SUBDOMAIN_ORIGIN, SameSiteStatus.STRICT, "Reloaded subdomain auxiliary navigations are strictly same-site.");
-  create_test(CROSS_SITE_ORIGIN, CROSS_SITE_ORIGIN, SameSiteStatus.LAX, "Reloaded ross-site auxiliary navigations are laxly same-site");
+  create_test(CROSS_SITE_ORIGIN, CROSS_SITE_ORIGIN, SameSiteStatus.LAX, "Reloaded cross-site auxiliary navigations are laxly same-site");
 </script>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-018.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-018.html
new file mode 100644
index 0000000..5d7ebc01
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-layout-018.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Layout containment stacking context</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-layout">
+<link rel="match" href="../reference/nothing.html">
+<meta name=assert content="Elements in which layout containment doesn't apply, do not create a stacking context.">
+<style>
+div {
+  display: inline;
+  contain: layout;
+  background: white;
+}
+span {
+  position: relative;
+  z-index: -1;
+}
+</style>
+
+<p>There should be nothing below.</p>
+<div><span>FAIL</span></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-025.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-025.html
new file mode 100644
index 0000000..0a41b62b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-paint-025.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Paint containment stacking context</title>
+<link rel="author" title="Manuel Rego Casasnovas" href="mailto:rego@igalia.com">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-paint">
+<link rel="match" href="../reference/nothing.html">
+<meta name=assert content="Elements in which paint containment doesn't apply, do not create a stacking context.">
+<style>
+div {
+  display: inline;
+  contain: paint;
+  background: white;
+}
+span {
+  position: relative;
+  z-index: -1;
+}
+</style>
+
+<p>There should be nothing below.</p>
+<div><span>FAIL</span></div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-grid-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-grid-002.html
new file mode 100644
index 0000000..1e7771e7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-grid-002.html
@@ -0,0 +1,41 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on grid container with explicit non-intrinsically sized tracks (and gaps)</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<meta name=assert content="grid-gap, grid-template-columns, and grid-template-rows do affect the size of the grid, even with size containment">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+
+<style>
+div {
+  position: absolute;
+}
+#red {
+  background: red;
+  width: 100px;
+  height: 100px;
+}
+#test {
+  background: green;
+
+  contain: size;
+  display: grid;
+  grid-gap: 20px;
+  grid-template-columns: auto 80px; /* 0 + 20 + 80 = 100 */
+  grid-template-rows: 40px 40px; /* 40 + 20 + 40 = 100 */
+  font-size: 800px;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id=red></div>
+<div id=test>&nbsp;</div>
+
+<!--
+The &nbsp;, auto sized column, and 800px font size
+are to make the test fail in browsers
+that do not implement contain:size at all,
+by making the box non square.
+-->
+
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-multicol-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-multicol-001.html
new file mode 100644
index 0000000..5c0dba9b7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/contain-size-multicol-001.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>CSS Containment Test: Size containment on a multicol with set column size (and gap)</title>
+<link rel="author" title="Florian Rivoal" href="https://florian.rivoal.net/">
+<link rel="help" href="https://drafts.csswg.org/css-contain-1/#containment-size">
+<meta name=assert content="columns and column-gap do affect the size of a multicol, even with size containment">
+<link rel="match" href="../reference/ref-filled-green-100px-square.xht">
+
+<style>
+div {
+  position: absolute;
+}
+#red {
+  background: red;
+  width: 100px;
+  height: 100px;
+}
+#test {
+  background: green;
+
+  columns: 2 40px;
+  column-gap: 20px;
+  min-height: 100px;
+
+  color: transparent;
+}
+</style>
+
+<p>Test passes if there is a filled green square and <strong>no red</strong>.</p>
+<div id=red></div>
+<div id=test>
+filler filler filler filler filler filler filler filler
+filler filler filler filler filler filler filler filler
+filler filler filler filler filler filler filler filler
+filler filler filler filler filler filler filler filler
+</div>
+
+<!--
+The filler text, min-height (instead of height) and transparent color
+are to make the test fail in browsers
+that do not implement contain:size at all,
+by making the box non square.
+-->
+
+
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/60x60-red.png b/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/60x60-red.png
deleted file mode 100644
index 823f125..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/css/css-contain/support/60x60-red.png
+++ /dev/null
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-flexbox/percentage-heights-quirks-node.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-flexbox/percentage-heights-quirks-node.html
new file mode 100644
index 0000000..4b254b4
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-flexbox/percentage-heights-quirks-node.html
@@ -0,0 +1,9 @@
+<title>In quirks mode a flex item should resolve its percentage height against its first ancestor with a defined height.</title>
+<link rel="help" href="https://quirks.spec.whatwg.org/#the-percentage-height-calculation-quirk">
+<link rel="match" href="../reference/ref-filled-green-100px-square-only.html">
+<p style="margin-top: 1em;">Test passes if there is a filled green square.</p>
+<div style="width: 200px; height: 200px;">
+  <div style="display: flex;">
+    <div style="width: 50%; height: 50%; background: green;"></div>
+  </div>
+</div>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/img-intrinsic-size-contribution-001.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/img-intrinsic-size-contribution-001.html
new file mode 100644
index 0000000..0850053
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/img-intrinsic-size-contribution-001.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html style="writing-mode: vertical-lr;">
+<title>CSS Test: intrinsic size contributions of images in vertical writing mode</title>
+<meta name="assert" content="The image's parent element's intrinsic inline size should be contributed to by the image's height, not the image's width">
+<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
+<link rel="author" title="Zhang Junzhi" href="mailto:zjz@zjz.name">
+<link rel="match" href="img-intrinsic-size-contribution-ref.html">
+
+<style>
+* { margin: 0; padding: 0; }
+</style>
+
+<div style="border: 1px solid blue; display: grid; height: 150px;">
+	<div style="border: 1px solid orange;">
+		<img src="support/blue-200x100.png">
+	</div>
+</div>
+
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/img-intrinsic-size-contribution-002.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/img-intrinsic-size-contribution-002.html
new file mode 100644
index 0000000..df0ccf20
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/img-intrinsic-size-contribution-002.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<html style="writing-mode: vertical-lr;">
+<title>CSS Test: intrinsic size contributions of images in vertical writing mode (with the image itself in horizontal writing mode)</title>
+<meta name="assert" content="The image's parent element's intrinsic inline size should be contributed to by the image's height, not the image's width">
+<link rel="help" href="http://www.w3.org/TR/css-writing-modes-3/#vertical-layout" title="7.1 Principles of Layout in Vertical Writing Modes">
+<link rel="author" title="Zhang Junzhi" href="mailto:zjz@zjz.name">
+<link rel="match" href="img-intrinsic-size-contribution-ref.html">
+
+<style>
+* { margin: 0; padding: 0; }
+</style>
+
+<div style="border: 1px solid blue; display: grid; height: 150px;">
+	<div style="border: 1px solid orange;">
+		<img src="support/blue-200x100.png" style="writing-mode: horizontal-tb;">
+	</div>
+</div>
+
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/img-intrinsic-size-contribution-ref.html b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/img-intrinsic-size-contribution-ref.html
new file mode 100644
index 0000000..ffda7d6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/img-intrinsic-size-contribution-ref.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+<title>CSS Test Reference: intrinsic size contributions of images in vertical writing mode</title>
+<link rel="author" title="Zhang Junzhi" href="mailto:zjz@zjz.name">
+
+<style>
+* { margin: 0; padding: 0; }
+</style>
+
+<div style="border: 1px solid blue; height: 150px; width: 202px;">
+	<div style="border: 1px solid orange; height: 148px;">
+		<img src="support/blue-200x100.png">
+	</div>
+</div>
+
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/support/blue-200x100.png b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/support/blue-200x100.png
new file mode 100644
index 0000000..e32c47dd
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/css/css-writing-modes/support/blue-200x100.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/cors/cors-preflight-not-cors-safelisted.any-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/cors/cors-preflight-not-cors-safelisted.any-expected.txt
deleted file mode 100644
index 56141bc..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/cors/cors-preflight-not-cors-safelisted.any-expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-This is a testharness.js-based test.
-PASS Loading data…
-FAIL Need CORS-preflight for accept/" header assert_equals: Preflight request has been made expected "1" but got "0"
-FAIL Need CORS-preflight for accept/012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678 header assert_equals: Preflight request has been made expected "1" but got "0"
-FAIL Need CORS-preflight for accept-language/ header assert_equals: Preflight request has been made expected "1" but got "0"
-FAIL Need CORS-preflight for accept-language/@ header assert_equals: Preflight request has been made expected "1" but got "0"
-FAIL Need CORS-preflight for content-language/ header assert_equals: Preflight request has been made expected "1" but got "0"
-FAIL Need CORS-preflight for content-language/@ header assert_equals: Preflight request has been made expected "1" but got "0"
-PASS Need CORS-preflight for content-type/text/html header
-FAIL Need CORS-preflight for content-type/text/plain; long=0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901 header assert_equals: Preflight request has been made expected "1" but got "0"
-PASS Need CORS-preflight for test/hi header
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/cors/cors-preflight-not-cors-safelisted.any.worker-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/cors/cors-preflight-not-cors-safelisted.any.worker-expected.txt
deleted file mode 100644
index 56141bc..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/cors/cors-preflight-not-cors-safelisted.any.worker-expected.txt
+++ /dev/null
@@ -1,13 +0,0 @@
-This is a testharness.js-based test.
-PASS Loading data…
-FAIL Need CORS-preflight for accept/" header assert_equals: Preflight request has been made expected "1" but got "0"
-FAIL Need CORS-preflight for accept/012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678 header assert_equals: Preflight request has been made expected "1" but got "0"
-FAIL Need CORS-preflight for accept-language/ header assert_equals: Preflight request has been made expected "1" but got "0"
-FAIL Need CORS-preflight for accept-language/@ header assert_equals: Preflight request has been made expected "1" but got "0"
-FAIL Need CORS-preflight for content-language/ header assert_equals: Preflight request has been made expected "1" but got "0"
-FAIL Need CORS-preflight for content-language/@ header assert_equals: Preflight request has been made expected "1" but got "0"
-PASS Need CORS-preflight for content-type/text/html header
-FAIL Need CORS-preflight for content-type/text/plain; long=0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901 header assert_equals: Preflight request has been made expected "1" but got "0"
-PASS Need CORS-preflight for test/hi header
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/headers/headers-no-cors.window-expected.txt b/third_party/WebKit/LayoutTests/external/wpt/fetch/api/headers/headers-no-cors.window-expected.txt
deleted file mode 100644
index 2241e22..0000000
--- a/third_party/WebKit/LayoutTests/external/wpt/fetch/api/headers/headers-no-cors.window-expected.txt
+++ /dev/null
@@ -1,18 +0,0 @@
-This is a testharness.js-based test.
-PASS Loading data…
-FAIL "no-cors" Headers object cannot have accept/" as header assert_false: expected false got true
-FAIL "no-cors" Headers object cannot have accept/012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678 as header assert_false: expected false got true
-FAIL "no-cors" Headers object cannot have accept-language/ as header assert_false: expected false got true
-FAIL "no-cors" Headers object cannot have accept-language/@ as header assert_false: expected false got true
-FAIL "no-cors" Headers object cannot have content-language/ as header assert_false: expected false got true
-FAIL "no-cors" Headers object cannot have content-language/@ as header assert_false: expected false got true
-PASS "no-cors" Headers object cannot have content-type/text/html as header
-FAIL "no-cors" Headers object cannot have content-type/text/plain; long=0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901 as header assert_false: expected false got true
-PASS "no-cors" Headers object cannot have test/hi as header
-FAIL "no-cors" Headers object cannot have dpr/2 as header assert_false: expected false got true
-PASS "no-cors" Headers object cannot have downlink/1 as header
-FAIL "no-cors" Headers object cannot have save-data/on as header assert_false: expected false got true
-FAIL "no-cors" Headers object cannot have viewport-width/100 as header assert_false: expected false got true
-FAIL "no-cors" Headers object cannot have width/100 as header assert_false: expected false got true
-Harness: the test ran to completion.
-
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-auto-margins-ref.html b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-auto-margins-ref.html
new file mode 100644
index 0000000..8b12587
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-auto-margins-ref.html
@@ -0,0 +1,37 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>legend inline auto margins</title>
+<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1488301">
+<style>
+body, html { padding:0; margin: 0; }
+div {
+  border: 1px solid black;
+  border-width: 10px 17px 7px 23px;
+  padding: 0;
+  margin: 0;
+  width: 448px;
+  height: 5px;
+  margin-top: 5px;
+  position: relative;
+}
+span {
+  position: absolute;
+  top: -15px;
+  width: 200px;
+  height: 20px;
+  padding: 0;
+  margin: 0;
+  background: grey;
+}
+center { width: 200px; height: 20px; background: red; }
+</style>
+</head>
+<body>
+  <div><span style="right:17px"></span></div>
+  <div><span style="left:31px"></span></div>
+  <div><span style="left:131px"></span></div>
+  <div><span style="right:32px"></span></div>
+  <div><span style="left:46px"></span></div>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-auto-margins.html b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-auto-margins.html
new file mode 100644
index 0000000..dd1964b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/legend-auto-margins.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>legend inline auto margins</title>
+<link rel="author" title="Mats Palmgren" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1488301">
+<link rel="match" href="legend-auto-margins-ref.html">
+<style>
+body, html { padding:0; margin: 0; }
+fieldset {
+  border: 1px solid black;
+  border-width: 10px 17px 7px 23px;
+  padding: 0 17px 0 31px;
+  margin: 0;
+  width: 400px;
+}
+legend {
+  width: 200px;
+  height: 20px;
+  padding: 0;
+  margin: 0;
+  background: grey;
+}
+</style>
+</head>
+<body>
+  <fieldset><legend style="margin-left:auto"></legend></fieldset>
+  <fieldset><legend style="margin-right:auto"></legend></fieldset>
+  <fieldset><legend style="margin:0 auto"></legend></fieldset>
+  <fieldset><legend style="margin:0 15px 0 auto"></legend></fieldset>
+  <fieldset><legend style="margin:0 auto 0 15px"></legend></fieldset>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/external/wpt/interfaces/trusted-types.tentative.idl b/third_party/WebKit/LayoutTests/external/wpt/interfaces/trusted-types.tentative.idl
new file mode 100644
index 0000000..a3a635b9
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/interfaces/trusted-types.tentative.idl
@@ -0,0 +1,53 @@
+// https://github.com/wicg/trusted-types
+
+typedef (DOMString or TrustedHTML) HTMLString;
+typedef (DOMString or TrustedScript) ScriptString;
+typedef (DOMString or TrustedScriptURL) ScriptURLString;
+typedef (USVString or TrustedURL) URLString;
+
+[Exposed=Window]
+interface TrustedHTML {
+    stringifier;
+};
+
+[Exposed=Window]
+interface TrustedScript {
+    stringifier;
+};
+
+[Exposed=Window]
+interface TrustedScriptURL {
+    stringifier;
+};
+
+[Exposed=Window]
+interface TrustedURL {
+    stringifier;
+};
+
+[Exposed=Window]
+interface TrustedTypePolicyFactory {
+    TrustedTypePolicy createPolicy(DOMString policyName, TrustedTypePolicyOptions policyOptions);
+    // All the policy object names that have been created
+    sequence<DOMString> getPolicyNames();
+};
+
+[Exposed=Window]
+interface TrustedTypePolicy {
+    readonly attribute DOMString name;
+    TrustedHTML createHTML(DOMString input);
+    TrustedScript createScript(DOMString input);
+    TrustedScriptURL createScriptURL(DOMString input);
+    TrustedURL createURL(DOMString input);
+};
+
+dictionary TrustedTypePolicyOptions {
+   CreateHTMLCallback createHTML;
+   CreateScriptCallback createScript;
+   CreateURLCallback createScriptURL;
+   CreateURLCallback createURL;
+};
+
+callback CreateHTMLCallback = DOMString (DOMString input);
+callback CreateScriptCallback = DOMString (DOMString input);
+callback CreateURLCallback = USVString (DOMString input);
diff --git a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-response/onpayerdetailchange-attribute.manual.https.html b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-response/onpayerdetailchange-attribute.manual.https.html
index 9f92d28..c8dd926 100644
--- a/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-response/onpayerdetailchange-attribute.manual.https.html
+++ b/third_party/WebKit/LayoutTests/external/wpt/payment-request/payment-response/onpayerdetailchange-attribute.manual.https.html
@@ -13,7 +13,7 @@
       response.addEventListener("payerdetailchange", resolve);
     });
     const error = button.previousElementSibling.textContent.trim();
-    const retryPromise = response.retry({ error });
+    await response.retry({ error });
     const event = await eventPromise;
     assert_true(event instanceof PaymentRequestUpdateEvent);
     for(const [prop, value] of Object.entries(expected)){
diff --git a/third_party/WebKit/LayoutTests/external/wpt/trusted-types/idlharness.window.js b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/idlharness.window.js
new file mode 100644
index 0000000..de136977
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/external/wpt/trusted-types/idlharness.window.js
@@ -0,0 +1,18 @@
+// META: script=/resources/WebIDLParser.js
+// META: script=/resources/idlharness.js
+
+idl_test(
+    ['trusted-types.tentative'],
+    ['dom', 'html'],
+    idl_array => {
+      idl_array.add_objects({
+        TrustedTypePolicyFactory: ['window.TrustedTypes'],
+        TrustedTypePolicy: ['window.TrustedTypes.createPolicy("SomeName", { createHTML: s => s })'],
+        TrustedHTML: ['window.TrustedTypes.createPolicy("SomeName1", { createHTML: s => s }).createHTML("A string")'],
+        TrustedScript: ['window.TrustedTypes.createPolicy("SomeName2", { createScript: s => s }).createScript("A string")'],
+        TrustedScriptURL: ['window.TrustedTypes.createPolicy("SomeName3", { createScriptURL: s => s }).createScriptURL("A string")'],
+        TrustedURL: ['window.TrustedTypes.createPolicy("SomeName4", { createURL: s => s }).createURL("A string")']
+      });
+    },
+    'Trusted Types'
+);
diff --git a/third_party/WebKit/LayoutTests/fast/css/case-transform-georgian-capital-expected.html b/third_party/WebKit/LayoutTests/fast/css/case-transform-georgian-capital-expected.html
new file mode 100644
index 0000000..298f6915
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/case-transform-georgian-capital-expected.html
@@ -0,0 +1,11 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+</head>
+<body>
+  <p>აჺჽჿ</p>
+  <p>აჺჽჿ</p>
+  <p>აჺჽჿ</p>
+  <p>აჺჽჿ</p>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/fast/css/case-transform-georgian-capital.html b/third_party/WebKit/LayoutTests/fast/css/case-transform-georgian-capital.html
new file mode 100644
index 0000000..a4ae638
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/fast/css/case-transform-georgian-capital.html
@@ -0,0 +1,13 @@
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
+</head>
+<body>
+  <!-- Test for temporary disabling of Georgian uppercasing. See
+    crbug.com/865427 . -->
+  <p style="text-transform:uppercase">აჺჽჿ</p>
+  <p style="text-transform:lowercase">აჺჽჿ</p>
+  <p style="text-transform:uppercase">ᲐᲺᲽᲿ</p>
+  <p style="text-transform:lowercase">ᲐᲺᲽᲿ</p>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/images/image-fragment-id-invalidation-expected.html b/third_party/WebKit/LayoutTests/http/tests/images/image-fragment-id-invalidation-expected.html
new file mode 100644
index 0000000..f718ea6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/images/image-fragment-id-invalidation-expected.html
@@ -0,0 +1,2 @@
+<!DOCTYPE html>
+<div style="width: 100px; height: 100px; background-color: green"></div>
diff --git a/third_party/WebKit/LayoutTests/http/tests/images/image-fragment-id-invalidation.html b/third_party/WebKit/LayoutTests/http/tests/images/image-fragment-id-invalidation.html
new file mode 100644
index 0000000..afc3768b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/images/image-fragment-id-invalidation.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<title>A background image gets updated when only the fragment changes</title>
+<script src="../resources/run-after-layout-and-paint.js"></script>
+<style>
+.green {
+  background: url(resources/sprites.svg#green) no-repeat;
+}
+.red {
+  background: url(resources/sprites.svg#red) no-repeat;
+}
+</style>
+<div id="target" class="red" style="width: 100px; height: 100px"></div>
+<script>
+runAfterLayoutAndPaint(function() {
+  target.className = "green";
+}, true);
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/images/resources/sprites.svg b/third_party/WebKit/LayoutTests/http/tests/images/resources/sprites.svg
new file mode 100644
index 0000000..eae75d1
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/images/resources/sprites.svg
@@ -0,0 +1,9 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+ <style>:root>svg{display:none}:root>svg:target{display:inline}</style>
+ <svg id="green" viewBox="0 0 100 100">
+   <rect fill="green" width="100" height="100"/>
+ </svg>
+ <svg id="red" viewBox="0 0 100 100">
+   <rect fill="red" width="100" height="100"/>
+ </svg>
+</svg>
diff --git a/third_party/WebKit/LayoutTests/http/tests/loading/sxg/resources/generate-test-sxgs.sh b/third_party/WebKit/LayoutTests/http/tests/loading/sxg/resources/generate-test-sxgs.sh
index 2b32f170..d4f77b54 100755
--- a/third_party/WebKit/LayoutTests/http/tests/loading/sxg/resources/generate-test-sxgs.sh
+++ b/third_party/WebKit/LayoutTests/http/tests/loading/sxg/resources/generate-test-sxgs.sh
@@ -41,6 +41,21 @@
   -o sxg-location.sxg \
   -miRecordSize 100
 
+# Generate the signed exchange file which also reports use counter info.
+gen-signedexchange \
+  -version 1b2 \
+  -uri https://127.0.0.1:8443/loading/sxg/resources/inner-url.html \
+  -status 200 \
+  -content sxg-usecounter.html \
+  -certificate $certs_dir/127.0.0.1.sxg.pem \
+  -certUrl https://127.0.0.1:8443/loading/sxg/resources/127.0.0.1.sxg.pem.cbor \
+  -validityUrl https://127.0.0.1:8443/loading/sxg/resources/resource.validity.msg \
+  -privateKey $certs_dir/127.0.0.1.sxg.key \
+  -date 2018-04-01T00:00:00Z \
+  -expire 168h \
+  -o sxg-usecounter.sxg \
+  -miRecordSize 100
+
 # Generate the signed exchange file which certificate file is not available.
 gen-signedexchange \
   -version 1b2 \
diff --git a/third_party/WebKit/LayoutTests/http/tests/loading/sxg/resources/sxg-usecounter.html b/third_party/WebKit/LayoutTests/http/tests/loading/sxg/resources/sxg-usecounter.html
new file mode 100644
index 0000000..1d6c83f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/loading/sxg/resources/sxg-usecounter.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<title>Content of SignedHTTPExchange</title>
+<script>
+const kSignedExchangeInnerResponse = 2541; // see web_feature.mojom
+
+window.addEventListener('message', (event) => {
+  const msg = {location: document.location.href, is_fallback: false};
+  if (window.internals) {
+    msg.is_use_counted = internals.isUseCounted(document, kSignedExchangeInnerResponse);
+  }
+
+  event.data.port.postMessage(msg);
+}, false);
+</script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/loading/sxg/resources/sxg-usecounter.sxg b/third_party/WebKit/LayoutTests/http/tests/loading/sxg/resources/sxg-usecounter.sxg
new file mode 100644
index 0000000..f8a4943
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/loading/sxg/resources/sxg-usecounter.sxg
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/http/tests/loading/sxg/sxg-usecounter.html b/third_party/WebKit/LayoutTests/http/tests/loading/sxg/sxg-usecounter.html
new file mode 100644
index 0000000..19e2737
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/loading/sxg/sxg-usecounter.html
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<title>SignedHTTPExchange UseCounter</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="./resources/sxg-util.js"></script>
+<body>
+<script>
+promise_test(async (t) => {
+  await waitUntilDidFinishLoadForFrame;
+
+  // The timestamp of the test SXG file is "Apr 1 2018 00:00 UTC" and valid
+  // until "Apr 8 2018 00:00 UTC".
+  await setSignedExchangeVerificationTime(new Date("Apr 1 2018 00:01 UTC"));
+
+  const event = await new Promise(async (resolve, reject) => {
+    // We can't catch the network error on iframe. So we use the timer.
+    t.step_timeout(() => reject('timeout'), 1000);
+
+    const frame =
+        await withIframe('resources/sxg-usecounter.sxg', 'sxg_iframe');
+    const channel = new MessageChannel();
+    channel.port1.onmessage = resolve;
+    frame.contentWindow.postMessage(
+        {port: channel.port2}, '*', [channel.port2]);
+  });
+  assert_equals(event.data.location, 'https://127.0.0.1:8443/loading/sxg/resources/inner-url.html');
+  assert_true(event.data.is_use_counted);
+  assert_false(event.data.is_fallback);
+}, 'SignedHTTPExchange inner response documents are use counted.');
+
+</script>
+</body>
diff --git a/third_party/WebKit/LayoutTests/svg/dom/resources/initial-value-helper.js b/third_party/WebKit/LayoutTests/svg/dom/resources/initial-value-helper.js
index 722ecf4..e417d58 100644
--- a/third_party/WebKit/LayoutTests/svg/dom/resources/initial-value-helper.js
+++ b/third_party/WebKit/LayoutTests/svg/dom/resources/initial-value-helper.js
@@ -1,9 +1,28 @@
 const objects = {
   SVGCircleElement: 'circle',
+  SVGClipPathElement: 'clipPath',
+  SVGComponentTransferFunctionElement: 'feFuncA',
   SVGEllipseElement: 'ellipse',
+  SVGFEBlendElement: 'feBlend',
+  SVGFEColorMatrixElement: 'feColorMatrix',
+  SVGFECompositeElement: 'feComposite',
+  SVGFEConvolveMatrixElement: 'feConvolveMatrix',
+  SVGFEDiffuseLightingElement: 'feDiffuseLighting',
+  SVGFEDisplacementMapElement: 'feDisplacementMap',
+  SVGFEDistantLightElement: 'feDistantLight',
+  SVGFEDropShadowElement: 'feDropShadow',
+  SVGFEGaussianBlurElement: 'feGaussianBlur',
+  SVGFEMorphologyElement: 'feMorphology',
+  SVGFEOffsetElement: 'feOffset',
+  SVGFEPointLightElement: 'fePointLight',
+  SVGFESpecularLightingElement: 'feSpecularLighting',
+  SVGFESpotLightElement: 'feSpotLight',
+  SVGFETurbulenceElement: 'feTurbulence',
   SVGFilterElement: 'filter',
   SVGFilterPrimitiveStandardAttributes: 'feBlend',
   SVGForeignObjectElement: 'foreignObject',
+  SVGGeometryElement: 'rect',
+  SVGGradientElement: 'linearGradient',
   SVGImageElement: 'image',
   SVGLineElement: 'line',
   SVGLinearGradientElement: 'linearGradient',
@@ -13,6 +32,7 @@
   SVGRadialGradientElement: 'radialGradient',
   SVGRectElement: 'rect',
   SVGSVGElement: 'svg',
+  SVGStopElement: 'stop',
   SVGTextContentElement: 'text',
   SVGTextPathElement: 'textPath',
   SVGUseElement: 'use',
diff --git a/third_party/WebKit/LayoutTests/svg/dom/svganimatedenumeration-initial-values.html b/third_party/WebKit/LayoutTests/svg/dom/svganimatedenumeration-initial-values.html
new file mode 100644
index 0000000..bb4a73f
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/svg/dom/svganimatedenumeration-initial-values.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<title>SVGAnimatedEnumeration, initial values</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/initial-value-helper.js"></script>
+<script>
+assert_initial_values([
+  { interface: 'SVGClipPathElement', attributes: [ 'clipPathUnits' ],
+    clipPathUnits: { initial: SVGUnitTypes.SVG_UNIT_TYPE_USERSPACEONUSE, valid: 'objectBoundingBox' } },
+  { interface: 'SVGComponentTransferFunctionElement', attributes: [ 'type' ],
+    type: { initial: SVGComponentTransferFunctionElement.SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY, valid: 'table' } },
+  { interface: 'SVGFEBlendElement', attributes: [ 'mode' ],
+    mode: { initial: SVGFEBlendElement.SVG_FEBLEND_MODE_NORMAL, valid: 'screen' } },
+  { interface: 'SVGFEColorMatrixElement', attributes: [ 'type' ],
+    type: { initial: SVGFEColorMatrixElement.SVG_FECOLORMATRIX_TYPE_MATRIX, valid: 'saturate' } },
+  { interface: 'SVGFECompositeElement', attributes: [ 'operator' ],
+    operator: { initial: SVGFECompositeElement.SVG_FECOMPOSITE_OPERATOR_OVER, valid: 'in' } },
+  { interface: 'SVGFEConvolveMatrixElement', attributes: [ 'edgeMode' ],
+    edgeMode: { initial: SVGFEConvolveMatrixElement.SVG_EDGEMODE_DUPLICATE, valid: 'wrap' } },
+  { interface: 'SVGFEDisplacementMapElement', attributes: [ 'xChannelSelector', 'yChannelSelector' ],
+    xChannelSelector: { initial: SVGFEDisplacementMapElement.SVG_CHANNEL_A, valid: 'R' },
+    yChannelSelector: { initial: SVGFEDisplacementMapElement.SVG_CHANNEL_A, valid: 'G' } },
+  { interface: 'SVGFEMorphologyElement', attributes: [ 'operator' ],
+    operator: { initial: SVGFEMorphologyElement.SVG_MORPHOLOGY_OPERATOR_ERODE, valid: 'dilate' } },
+  { interface: 'SVGFETurbulenceElement', attributes: [ 'stitchTiles', 'type' ],
+    stitchTiles: { initial: SVGFETurbulenceElement.SVG_STITCHTYPE_NOSTITCH, valid: 'stitch' },
+    type: { initial: SVGFETurbulenceElement.SVG_TURBULENCE_TYPE_TURBULENCE, valid: 'fractalNoise' } },
+  { interface: 'SVGFilterElement', attributes: [ 'filterUnits', 'primitiveUnits' ],
+    filterUnits: { initial: SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX, valid: 'userSpaceOnUse' },
+    primitiveUnits: { initial: SVGUnitTypes.SVG_UNIT_TYPE_USERSPACEONUSE, valid: 'objectBoundingBox' } },
+  { interface: 'SVGGradientElement', attributes: [ 'gradientUnits', 'spreadMethod' ],
+    gradientUnits: { initial: SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX, valid: 'userSpaceOnUse' },
+    spreadMethod: { initial: SVGGradientElement.SVG_SPREADMETHOD_PAD, valid: 'repeat' } },
+  { interface: 'SVGMarkerElement', attributes: [ 'markerUnits', 'orientType' ],
+    markerUnits: { initial: SVGMarkerElement.SVG_MARKERUNITS_STROKEWIDTH, valid: 'userSpaceOnUse' },
+    orientType: { initial: SVGMarkerElement.SVG_MARKER_ORIENT_ANGLE, valid: 'auto' } },
+  { interface: 'SVGMaskElement', attributes: [ 'maskUnits', 'maskContentUnits' ],
+    maskUnits: { initial: SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX, valid: 'userSpaceOnUse' },
+    maskContentUnits: { initial: SVGUnitTypes.SVG_UNIT_TYPE_USERSPACEONUSE, valid: 'objectBoundingBox' } },
+  { interface: 'SVGPatternElement', attributes: [ 'patternUnits', 'patternContentUnits' ],
+    patternUnits: { initial: SVGUnitTypes.SVG_UNIT_TYPE_OBJECTBOUNDINGBOX, valid: 'userSpaceOnUse' },
+    patternContentUnits: { initial: SVGUnitTypes.SVG_UNIT_TYPE_USERSPACEONUSE, valid: 'objectBoundingBox' } },
+  { interface: 'SVGTextContentElement', attributes: [ 'lengthAdjust' ],
+    lengthAdjust: { initial: SVGTextContentElement.LENGTHADJUST_SPACING, valid: 'spacingAndGlyphs' } },
+  { interface: 'SVGTextPathElement', attributes: [ 'method', 'spacing' ],
+    method: { initial: SVGTextPathElement.TEXTPATH_METHODTYPE_ALIGN, valid: 'stretch' },
+    spacing: { initial: SVGTextPathElement.TEXTPATH_SPACINGTYPE_EXACT, valid: 'auto' } },
+], { mapProperty: { orientType: 'orient' } });
+</script>
diff --git a/third_party/WebKit/LayoutTests/svg/dom/svganimatednumber-initial-values.html b/third_party/WebKit/LayoutTests/svg/dom/svganimatednumber-initial-values.html
new file mode 100644
index 0000000..45625e2
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/svg/dom/svganimatednumber-initial-values.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<title>SVGAnimatedNumber, initial values</title>
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<script src="resources/initial-value-helper.js"></script>
+<script>
+// Map from IDL attribute to content attribute:
+const propertyToAttributeMap = {
+  kernelUnitLengthX: 'kernelUnitLength',
+  kernelUnitLengthY: 'kernelUnitLength',
+  baseFrequencyX: 'baseFrequency',
+  baseFrequencyY: 'baseFrequency',
+  stdDeviationX: 'stdDeviation',
+  stdDeviationY: 'stdDeviation',
+  radiusX: 'radius',
+  radiusY: 'radius',
+};
+
+assert_initial_values([
+  { interface: 'SVGComponentTransferFunctionElement',
+    attributes: [ 'slope', 'intercept', 'amplitude', 'exponent', 'offset' ],
+    slope: { initial: 1 }, amplitude: { initial: 1 }, exponent: { initial: 1 } },
+  { interface: 'SVGFECompositeElement', attributes: [ 'k1', 'k2', 'k3', 'k4' ] },
+  { interface: 'SVGFEConvolveMatrixElement',
+    attributes: [ 'divisor', 'bias', 'kernelUnitLengthX', 'kernelUnitLengthY' ],
+    divisor: { initial: 1 } },
+  { interface: 'SVGFEDiffuseLightingElement',
+    attributes: [ 'surfaceScale', 'diffuseConstant', 'kernelUnitLengthX', 'kernelUnitLengthY' ],
+    diffuseConstant: { initial: 1 }, surfaceScale: { initial: 1 } },
+  { interface: 'SVGFEDisplacementMapElement', attributes: [ 'scale' ] },
+  { interface: 'SVGFEDistantLightElement', attributes: [ 'azimuth', 'elevation' ] },
+  { interface: 'SVGFEDropShadowElement',
+    attributes: [ 'dx', 'dy', 'stdDeviationX', 'stdDeviationY' ],
+    dx: { initial: 2 }, dy: { initial: 2 }, stdDeviationX: { initial: 2 },  stdDeviationY: { initial: 2 } },
+  { interface: 'SVGFEGaussianBlurElement', attributes: [ 'stdDeviationX', 'stdDeviationY' ] },
+  { interface: 'SVGFEMorphologyElement', attributes: [ 'radiusX', 'radiusY' ] },
+  { interface: 'SVGFEOffsetElement', attributes: [ 'dx', 'dy' ] },
+  { interface: 'SVGFEPointLightElement', attributes: [ 'x', 'y', 'z' ] },
+  { interface: 'SVGFESpecularLightingElement',
+    attributes: [ 'surfaceScale', 'specularConstant', 'specularExponent', 'kernelUnitLengthX', 'kernelUnitLengthY' ],
+    specularConstant: { initial: 1 }, specularExponent: { initial: 1 }, surfaceScale: { initial: 1 } },
+  { interface: 'SVGFESpotLightElement',
+    attributes: [ 'x', 'y', 'z', 'pointsAtX', 'pointsAtY', 'pointsAtZ', 'specularExponent', 'limitingConeAngle' ],
+    specularExponent: { initial: 1 } },
+  { interface: 'SVGFETurbulenceElement', attributes: [ 'baseFrequencyX', 'baseFrequencyY', 'seed' ] },
+  { interface: 'SVGGeometryElement', attributes: [ 'pathLength' ] },
+  { interface: 'SVGStopElement', attributes: [ 'offset' ] },
+], { initial: 0, valid: '42', mapProperty: propertyToAttributeMap });
+</script>
diff --git a/third_party/WebKit/LayoutTests/svg/dom/systemLanguage-comma-separated.html b/third_party/WebKit/LayoutTests/svg/dom/systemLanguage-comma-separated.html
new file mode 100644
index 0000000..99c8fa69
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/svg/dom/systemLanguage-comma-separated.html
@@ -0,0 +1,18 @@
+<!DOCTYPE HTML>
+<title>The "systemLanguage" is a COMMA-separated list of langtags</title>
+<link rel="help" href="https://www.w3.org/TR/SVG2/struct.html#ConditionalProcessingSystemLanguageAttribute">
+<script src="../../resources/testharness.js"></script>
+<script src="../../resources/testharnessreport.js"></script>
+<svg>
+	<text systemLanguage="en-US, zh-Hans,zh-Hant" id="switchtest"></text>
+</svg>
+<script>
+test(() => {
+	var systemLanguage_langtagList = document.getElementById("switchtest").systemLanguage;
+	assert_equals(systemLanguage_langtagList.numberOfItems, 3, 'The number of langtag should be 3');
+	assert_equals(systemLanguage_langtagList.getItem(0), 'en-US');
+	assert_equals(systemLanguage_langtagList.getItem(1), 'zh-Hans');
+	assert_equals(systemLanguage_langtagList.getItem(2), 'zh-Hant');
+});
+
+</script>
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
index f78fb22..5bf5cf2e 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/element-instance-property-listing-expected.txt
@@ -142,6 +142,8 @@
     property onended
     property onerror
     property onfocus
+    property onfullscreenchange
+    property onfullscreenerror
     property ongotpointercapture
     property oninput
     property oninvalid
@@ -217,6 +219,7 @@
     property removeEventListener
     property replaceChild
     property replaceWith
+    property requestFullscreen
     property requestPointerLock
     property scroll
     property scrollBy
@@ -1225,6 +1228,8 @@
     property onended
     property onerror
     property onfocus
+    property onfullscreenchange
+    property onfullscreenerror
     property ongotpointercapture
     property oninput
     property oninvalid
@@ -1300,6 +1305,7 @@
     property removeEventListener
     property replaceChild
     property replaceWith
+    property requestFullscreen
     property requestPointerLock
     property scroll
     property scrollBy
diff --git a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
index b10e54fc..d8b047e 100644
--- a/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/virtual/stable/webexposed/global-interface-listing-expected.txt
@@ -1174,6 +1174,9 @@
     getter firstElementChild
     getter fonts
     getter forms
+    getter fullscreen
+    getter fullscreenElement
+    getter fullscreenEnabled
     getter head
     getter hidden
     getter images
@@ -1213,6 +1216,8 @@
     getter onerror
     getter onfocus
     getter onfreeze
+    getter onfullscreenchange
+    getter onfullscreenerror
     getter ongotpointercapture
     getter oninput
     getter oninvalid
@@ -1324,6 +1329,7 @@
     method elementsFromPoint
     method evaluate
     method execCommand
+    method exitFullscreen
     method exitPictureInPicture
     method exitPointerLock
     method getElementById
@@ -1357,6 +1363,9 @@
     setter dir
     setter domain
     setter fgColor
+    setter fullscreen
+    setter fullscreenElement
+    setter fullscreenEnabled
     setter linkColor
     setter onabort
     setter onauxclick
@@ -1388,6 +1397,8 @@
     setter onerror
     setter onfocus
     setter onfreeze
+    setter onfullscreenchange
+    setter onfullscreenerror
     setter ongotpointercapture
     setter oninput
     setter oninvalid
@@ -1516,6 +1527,8 @@
     getter onbeforepaste
     getter oncopy
     getter oncut
+    getter onfullscreenchange
+    getter onfullscreenerror
     getter onpaste
     getter onsearch
     getter onselectstart
@@ -1568,6 +1581,7 @@
     method removeAttributeNS
     method removeAttributeNode
     method replaceWith
+    method requestFullscreen
     method requestPointerLock
     method scroll
     method scrollBy
@@ -1592,6 +1606,8 @@
     setter onbeforepaste
     setter oncopy
     setter oncut
+    setter onfullscreenchange
+    setter onfullscreenerror
     setter onpaste
     setter onsearch
     setter onselectstart
@@ -6261,6 +6277,7 @@
     attribute @@toStringTag
     getter activeElement
     getter delegatesFocus
+    getter fullscreenElement
     getter host
     getter innerHTML
     getter mode
@@ -6271,6 +6288,7 @@
     method elementFromPoint
     method elementsFromPoint
     method getSelection
+    setter fullscreenElement
     setter innerHTML
 interface SharedWorker : EventTarget
     attribute @@toStringTag
diff --git a/third_party/WebKit/LayoutTests/virtual/sxg-origin-trial-with-network-service/http/tests/loading/sxg/sxg-usecounter-expected.txt b/third_party/WebKit/LayoutTests/virtual/sxg-origin-trial-with-network-service/http/tests/loading/sxg/sxg-usecounter-expected.txt
new file mode 100644
index 0000000..9fbbef8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/sxg-origin-trial-with-network-service/http/tests/loading/sxg/sxg-usecounter-expected.txt
@@ -0,0 +1,13 @@
+main frame - didStartProvisionalLoadForFrame
+main frame - didCommitLoadForFrame
+main frame - didReceiveTitle: SignedHTTPExchange UseCounter
+main frame - didFinishDocumentLoadForFrame
+main frame - didHandleOnloadEventsForFrame
+main frame - didFinishLoadForFrame
+frame "sxg_iframe" - didReceiveTitle: 
+frame "sxg_iframe" - didStartProvisionalLoadForFrame
+frame "sxg_iframe" - didFailProvisionalLoadWithError
+This is a testharness.js-based test.
+FAIL SignedHTTPExchange inner response documents are use counted. promise_test: Unhandled rejection with value: "timeout"
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/virtual/sxg-origin-trial/http/tests/loading/sxg/sxg-usecounter-expected.txt b/third_party/WebKit/LayoutTests/virtual/sxg-origin-trial/http/tests/loading/sxg/sxg-usecounter-expected.txt
new file mode 100644
index 0000000..9fbbef8
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/virtual/sxg-origin-trial/http/tests/loading/sxg/sxg-usecounter-expected.txt
@@ -0,0 +1,13 @@
+main frame - didStartProvisionalLoadForFrame
+main frame - didCommitLoadForFrame
+main frame - didReceiveTitle: SignedHTTPExchange UseCounter
+main frame - didFinishDocumentLoadForFrame
+main frame - didHandleOnloadEventsForFrame
+main frame - didFinishLoadForFrame
+frame "sxg_iframe" - didReceiveTitle: 
+frame "sxg_iframe" - didStartProvisionalLoadForFrame
+frame "sxg_iframe" - didFailProvisionalLoadWithError
+This is a testharness.js-based test.
+FAIL SignedHTTPExchange inner response documents are use counted. promise_test: Unhandled rejection with value: "timeout"
+Harness: the test ran to completion.
+
diff --git a/third_party/blink/common/BUILD.gn b/third_party/blink/common/BUILD.gn
index 3da7954..5f62cbb 100644
--- a/third_party/blink/common/BUILD.gn
+++ b/third_party/blink/common/BUILD.gn
@@ -38,15 +38,18 @@
     "indexeddb/indexeddb_struct_traits.cc",
     "manifest/manifest.cc",
     "manifest/manifest_icon_selector.cc",
-    "message_port/cloneable_message.cc",
-    "message_port/cloneable_message_struct_traits.cc",
-    "message_port/cloneable_message_struct_traits.h",
-    "message_port/message_port_channel.cc",
-    "message_port/string_message_codec.cc",
-    "message_port/transferable_message.cc",
-    "message_port/transferable_message_struct_traits.cc",
-    "message_port/transferable_message_struct_traits.h",
+    "messaging/cloneable_message.cc",
+    "messaging/cloneable_message_struct_traits.cc",
+    "messaging/cloneable_message_struct_traits.h",
+    "messaging/message_port_channel.cc",
+    "messaging/string_message_codec.cc",
+    "messaging/transferable_message.cc",
+    "messaging/transferable_message_struct_traits.cc",
+    "messaging/transferable_message_struct_traits.h",
     "mime_util/mime_util.cc",
+    "notifications/notification_resources.cc",
+    "notifications/notification_struct_traits.cc",
+    "notifications/platform_notification_data.cc",
     "origin_policy/origin_policy.cc",
     "origin_policy/origin_policy_parser.cc",
     "origin_policy/origin_policy_parser.h",
@@ -108,6 +111,7 @@
     "indexeddb/indexeddb_key_unittest.cc",
     "manifest/manifest_icon_selector_unittest.cc",
     "mime_util/mime_util_unittest.cc",
+    "notifications/notification_struct_traits_unittest.cc",
     "origin_policy/origin_policy_unittest.cc",
     "origin_trials/trial_token_unittest.cc",
     "origin_trials/trial_token_validator_unittest.cc",
@@ -117,10 +121,13 @@
   deps = [
     "//base",
     "//base/test:test_support",
+    "//mojo/core/embedder",
     "//net",
+    "//skia/public/interfaces",
     "//testing/gtest",
     "//third_party/blink/public/common:headers",
     "//third_party/boringssl",
+    "//url/mojom:url_mojom_gurl",
     "//v8",
     "//v8:v8_libplatform",
   ]
@@ -129,7 +136,7 @@
     # TODO(crbug.com/845384): Enable these tests also on Android. Currently
     # they are excluded as they require V8 environment but V8 snapshot is
     # not available in the current minimum test setting.
-    sources += [ "message_port/string_message_codec_unittest.cc" ]
+    sources += [ "messaging/string_message_codec_unittest.cc" ]
   } else {
     # is_android
     sources += [
diff --git a/third_party/blink/common/message_port/cloneable_message.typemap b/third_party/blink/common/message_port/cloneable_message.typemap
deleted file mode 100644
index cae1c8f5..0000000
--- a/third_party/blink/common/message_port/cloneable_message.typemap
+++ /dev/null
@@ -1,13 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//third_party/blink/public/mojom/message_port/message_port.mojom"
-public_headers =
-    [ "//third_party/blink/public/common/message_port/cloneable_message.h" ]
-traits_headers = [
-  "//third_party/blink/common/message_port/cloneable_message_struct_traits.h",
-]
-
-type_mappings =
-    [ "blink.mojom.CloneableMessage=::blink::CloneableMessage[move_only]" ]
diff --git a/third_party/blink/common/message_port/transferable_message.typemap b/third_party/blink/common/message_port/transferable_message.typemap
deleted file mode 100644
index e13c3f5..0000000
--- a/third_party/blink/common/message_port/transferable_message.typemap
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright 2017 The Chromium Authors. All rights reserved.
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-mojom = "//third_party/blink/public/mojom/message_port/message_port.mojom"
-public_headers = [
-  "//third_party/blink/public/common/message_port/transferable_message.h",
-  "//third_party/blink/public/common/message_port/message_port_channel.h",
-]
-traits_headers = [ "//third_party/blink/common/message_port/transferable_message_struct_traits.h" ]
-
-deps = [
-  "//skia/public/interfaces",
-]
-type_mappings = [
-  "blink.mojom.TransferableMessage=::blink::TransferableMessage[move_only]",
-]
diff --git a/third_party/blink/common/message_port/OWNERS b/third_party/blink/common/messaging/OWNERS
similarity index 100%
rename from third_party/blink/common/message_port/OWNERS
rename to third_party/blink/common/messaging/OWNERS
diff --git a/third_party/blink/common/message_port/cloneable_message.cc b/third_party/blink/common/messaging/cloneable_message.cc
similarity index 91%
rename from third_party/blink/common/message_port/cloneable_message.cc
rename to third_party/blink/common/messaging/cloneable_message.cc
index 5e431b4..a2076ae 100644
--- a/third_party/blink/common/message_port/cloneable_message.cc
+++ b/third_party/blink/common/messaging/cloneable_message.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/public/common/message_port/cloneable_message.h"
+#include "third_party/blink/public/common/messaging/cloneable_message.h"
 
 #include "third_party/blink/public/mojom/blob/blob.mojom.h"
-#include "third_party/blink/public/mojom/message_port/message_port.mojom.h"
+#include "third_party/blink/public/mojom/messaging/message_port.mojom.h"
 
 namespace blink {
 
diff --git a/third_party/blink/common/messaging/cloneable_message.typemap b/third_party/blink/common/messaging/cloneable_message.typemap
new file mode 100644
index 0000000..790a1e1
--- /dev/null
+++ b/third_party/blink/common/messaging/cloneable_message.typemap
@@ -0,0 +1,12 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//third_party/blink/public/mojom/messaging/message_port.mojom"
+public_headers =
+    [ "//third_party/blink/public/common/messaging/cloneable_message.h" ]
+traits_headers =
+    [ "//third_party/blink/common/messaging/cloneable_message_struct_traits.h" ]
+
+type_mappings =
+    [ "blink.mojom.CloneableMessage=::blink::CloneableMessage[move_only]" ]
diff --git a/third_party/blink/common/message_port/cloneable_message_struct_traits.cc b/third_party/blink/common/messaging/cloneable_message_struct_traits.cc
similarity index 94%
rename from third_party/blink/common/message_port/cloneable_message_struct_traits.cc
rename to third_party/blink/common/messaging/cloneable_message_struct_traits.cc
index 0d62abc..3ad4d884 100644
--- a/third_party/blink/common/message_port/cloneable_message_struct_traits.cc
+++ b/third_party/blink/common/messaging/cloneable_message_struct_traits.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/common/message_port/cloneable_message_struct_traits.h"
+#include "third_party/blink/common/messaging/cloneable_message_struct_traits.h"
 
 #include "base/containers/span.h"
 #include "mojo/public/cpp/base/big_buffer_mojom_traits.h"
diff --git a/third_party/blink/common/message_port/cloneable_message_struct_traits.h b/third_party/blink/common/messaging/cloneable_message_struct_traits.h
similarity index 78%
rename from third_party/blink/common/message_port/cloneable_message_struct_traits.h
rename to third_party/blink/common/messaging/cloneable_message_struct_traits.h
index 27860b8..0b20cf4 100644
--- a/third_party/blink/common/message_port/cloneable_message_struct_traits.h
+++ b/third_party/blink/common/messaging/cloneable_message_struct_traits.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_COMMON_MESSAGE_PORT_CLONEABLE_MESSAGE_STRUCT_TRAITS_H_
-#define THIRD_PARTY_BLINK_COMMON_MESSAGE_PORT_CLONEABLE_MESSAGE_STRUCT_TRAITS_H_
+#ifndef THIRD_PARTY_BLINK_COMMON_MESSAGING_CLONEABLE_MESSAGE_STRUCT_TRAITS_H_
+#define THIRD_PARTY_BLINK_COMMON_MESSAGING_CLONEABLE_MESSAGE_STRUCT_TRAITS_H_
 
 #include "mojo/public/cpp/base/big_buffer.h"
 #include "mojo/public/cpp/base/unguessable_token_mojom_traits.h"
-#include "third_party/blink/public/common/message_port/cloneable_message.h"
-#include "third_party/blink/public/mojom/message_port/message_port.mojom.h"
+#include "third_party/blink/public/common/messaging/cloneable_message.h"
+#include "third_party/blink/public/mojom/messaging/message_port.mojom.h"
 
 namespace mojo {
 
@@ -49,4 +49,4 @@
 
 }  // namespace mojo
 
-#endif  // THIRD_PARTY_BLINK_COMMON_MESSAGE_PORT_CLONEABLE_MESSAGE_STRUCT_TRAITS_H_
+#endif  // THIRD_PARTY_BLINK_COMMON_MESSAGING_CLONEABLE_MESSAGE_STRUCT_TRAITS_H_
diff --git a/third_party/blink/common/message_port/message_port_channel.cc b/third_party/blink/common/messaging/message_port_channel.cc
similarity index 95%
rename from third_party/blink/common/message_port/message_port_channel.cc
rename to third_party/blink/common/messaging/message_port_channel.cc
index 96d430b..dcc6842 100644
--- a/third_party/blink/common/message_port/message_port_channel.cc
+++ b/third_party/blink/common/messaging/message_port_channel.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
 
 namespace blink {
 
diff --git a/third_party/blink/common/message_port/string_message_codec.cc b/third_party/blink/common/messaging/string_message_codec.cc
similarity index 97%
rename from third_party/blink/common/message_port/string_message_codec.cc
rename to third_party/blink/common/messaging/string_message_codec.cc
index 45f5e26..77db82f7 100644
--- a/third_party/blink/common/message_port/string_message_codec.cc
+++ b/third_party/blink/common/messaging/string_message_codec.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/public/common/message_port/string_message_codec.h"
+#include "third_party/blink/public/common/messaging/string_message_codec.h"
 
 #include <vector>
 
diff --git a/third_party/blink/common/message_port/string_message_codec_unittest.cc b/third_party/blink/common/messaging/string_message_codec_unittest.cc
similarity index 98%
rename from third_party/blink/common/message_port/string_message_codec_unittest.cc
rename to third_party/blink/common/messaging/string_message_codec_unittest.cc
index 374d865..1f858bce 100644
--- a/third_party/blink/common/message_port/string_message_codec_unittest.cc
+++ b/third_party/blink/common/messaging/string_message_codec_unittest.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/public/common/message_port/string_message_codec.h"
+#include "third_party/blink/public/common/messaging/string_message_codec.h"
 
 #include "base/strings/utf_string_conversions.h"
 #include "base/test/scoped_task_environment.h"
diff --git a/third_party/blink/common/message_port/transferable_message.cc b/third_party/blink/common/messaging/transferable_message.cc
similarity index 85%
rename from third_party/blink/common/message_port/transferable_message.cc
rename to third_party/blink/common/messaging/transferable_message.cc
index 3dd003b..3388e5e8 100644
--- a/third_party/blink/common/message_port/transferable_message.cc
+++ b/third_party/blink/common/messaging/transferable_message.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/public/common/message_port/transferable_message.h"
+#include "third_party/blink/public/common/messaging/transferable_message.h"
 
 namespace blink {
 
diff --git a/third_party/blink/common/messaging/transferable_message.typemap b/third_party/blink/common/messaging/transferable_message.typemap
new file mode 100644
index 0000000..290f8fab
--- /dev/null
+++ b/third_party/blink/common/messaging/transferable_message.typemap
@@ -0,0 +1,19 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//third_party/blink/public/mojom/messaging/message_port.mojom"
+public_headers = [
+  "//third_party/blink/public/common/messaging/transferable_message.h",
+  "//third_party/blink/public/common/messaging/message_port_channel.h",
+]
+traits_headers = [
+  "//third_party/blink/common/messaging/transferable_message_struct_traits.h",
+]
+
+deps = [
+  "//skia/public/interfaces",
+]
+type_mappings = [
+  "blink.mojom.TransferableMessage=::blink::TransferableMessage[move_only]",
+]
diff --git a/third_party/blink/common/message_port/transferable_message_struct_traits.cc b/third_party/blink/common/messaging/transferable_message_struct_traits.cc
similarity index 86%
rename from third_party/blink/common/message_port/transferable_message_struct_traits.cc
rename to third_party/blink/common/messaging/transferable_message_struct_traits.cc
index fba548a..3cf0e00 100644
--- a/third_party/blink/common/message_port/transferable_message_struct_traits.cc
+++ b/third_party/blink/common/messaging/transferable_message_struct_traits.cc
@@ -2,10 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "third_party/blink/common/message_port/transferable_message_struct_traits.h"
+#include "third_party/blink/common/messaging/transferable_message_struct_traits.h"
 
 #include "base/containers/span.h"
-#include "third_party/blink/common/message_port/cloneable_message_struct_traits.h"
+#include "third_party/blink/common/messaging/cloneable_message_struct_traits.h"
 
 namespace mojo {
 
diff --git a/third_party/blink/common/message_port/transferable_message_struct_traits.h b/third_party/blink/common/messaging/transferable_message_struct_traits.h
similarity index 76%
rename from third_party/blink/common/message_port/transferable_message_struct_traits.h
rename to third_party/blink/common/messaging/transferable_message_struct_traits.h
index 2bf79e69..434d205c 100644
--- a/third_party/blink/common/message_port/transferable_message_struct_traits.h
+++ b/third_party/blink/common/messaging/transferable_message_struct_traits.h
@@ -2,13 +2,13 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_COMMON_MESSAGE_PORT_TRANSFERABLE_MESSAGE_STRUCT_TRAITS_H_
-#define THIRD_PARTY_BLINK_COMMON_MESSAGE_PORT_TRANSFERABLE_MESSAGE_STRUCT_TRAITS_H_
+#ifndef THIRD_PARTY_BLINK_COMMON_MESSAGING_TRANSFERABLE_MESSAGE_STRUCT_TRAITS_H_
+#define THIRD_PARTY_BLINK_COMMON_MESSAGING_TRANSFERABLE_MESSAGE_STRUCT_TRAITS_H_
 
 #include "skia/public/interfaces/bitmap_skbitmap_struct_traits.h"
-#include "third_party/blink/common/message_port/cloneable_message_struct_traits.h"
-#include "third_party/blink/public/common/message_port/transferable_message.h"
-#include "third_party/blink/public/mojom/message_port/message_port.mojom.h"
+#include "third_party/blink/common/messaging/cloneable_message_struct_traits.h"
+#include "third_party/blink/public/common/messaging/transferable_message.h"
+#include "third_party/blink/public/mojom/messaging/message_port.mojom.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
 namespace mojo {
@@ -51,4 +51,4 @@
 
 }  // namespace mojo
 
-#endif  // THIRD_PARTY_BLINK_COMMON_MESSAGE_PORT_TRANSFERABLE_MESSAGE_STRUCT_TRAITS_H_
+#endif  // THIRD_PARTY_BLINK_COMMON_MESSAGING_TRANSFERABLE_MESSAGE_STRUCT_TRAITS_H_
diff --git a/content/common/notifications/OWNERS b/third_party/blink/common/notifications/OWNERS
similarity index 100%
rename from content/common/notifications/OWNERS
rename to third_party/blink/common/notifications/OWNERS
diff --git a/content/public/common/notification_resources.cc b/third_party/blink/common/notifications/notification_resources.cc
similarity index 74%
rename from content/public/common/notification_resources.cc
rename to third_party/blink/common/notifications/notification_resources.cc
index 75619a0a..e457ab5 100644
--- a/content/public/common/notification_resources.cc
+++ b/third_party/blink/common/notifications/notification_resources.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/public/common/notification_resources.h"
+#include "third_party/blink/public/common/notifications/notification_resources.h"
 
-namespace content {
+namespace blink {
 
 NotificationResources::NotificationResources() {}
 
@@ -13,4 +13,4 @@
 
 NotificationResources::~NotificationResources() {}
 
-}  // namespace content
+}  // namespace blink
diff --git a/content/common/notifications/notification_struct_traits.cc b/third_party/blink/common/notifications/notification_struct_traits.cc
similarity index 73%
rename from content/common/notifications/notification_struct_traits.cc
rename to third_party/blink/common/notifications/notification_struct_traits.cc
index 4877f361..97248882 100644
--- a/content/common/notifications/notification_struct_traits.cc
+++ b/third_party/blink/common/notifications/notification_struct_traits.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/common/notifications/notification_struct_traits.h"
+#include "third_party/blink/public/common/notifications/notification_struct_traits.h"
 
 namespace {
 
@@ -26,7 +26,7 @@
 }
 
 bool ValidateActions(
-    const std::vector<content::PlatformNotificationAction>& actions) {
+    const std::vector<blink::PlatformNotificationAction>& actions) {
   return actions.size() <= kMaximumActions;
 }
 
@@ -43,15 +43,15 @@
 using blink::mojom::NotificationActionType;
 
 // static
-NotificationDirection EnumTraits<NotificationDirection,
-                                 content::PlatformNotificationData::Direction>::
-    ToMojom(content::PlatformNotificationData::Direction input) {
+NotificationDirection
+EnumTraits<NotificationDirection, blink::PlatformNotificationData::Direction>::
+    ToMojom(blink::PlatformNotificationData::Direction input) {
   switch (input) {
-    case content::PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT:
+    case blink::PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT:
       return NotificationDirection::LEFT_TO_RIGHT;
-    case content::PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT:
+    case blink::PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT:
       return NotificationDirection::RIGHT_TO_LEFT;
-    case content::PlatformNotificationData::DIRECTION_AUTO:
+    case blink::PlatformNotificationData::DIRECTION_AUTO:
       return NotificationDirection::AUTO;
   }
 
@@ -61,18 +61,18 @@
 
 // static
 bool EnumTraits<NotificationDirection,
-                content::PlatformNotificationData::Direction>::
+                blink::PlatformNotificationData::Direction>::
     FromMojom(NotificationDirection input,
-              content::PlatformNotificationData::Direction* out) {
+              blink::PlatformNotificationData::Direction* out) {
   switch (input) {
     case NotificationDirection::LEFT_TO_RIGHT:
-      *out = content::PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT;
+      *out = blink::PlatformNotificationData::DIRECTION_LEFT_TO_RIGHT;
       return true;
     case NotificationDirection::RIGHT_TO_LEFT:
-      *out = content::PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT;
+      *out = blink::PlatformNotificationData::DIRECTION_RIGHT_TO_LEFT;
       return true;
     case NotificationDirection::AUTO:
-      *out = content::PlatformNotificationData::DIRECTION_AUTO;
+      *out = blink::PlatformNotificationData::DIRECTION_AUTO;
       return true;
   }
 
@@ -81,12 +81,12 @@
 
 // static
 NotificationActionType
-EnumTraits<NotificationActionType, content::PlatformNotificationActionType>::
-    ToMojom(content::PlatformNotificationActionType input) {
+EnumTraits<NotificationActionType, blink::PlatformNotificationActionType>::
+    ToMojom(blink::PlatformNotificationActionType input) {
   switch (input) {
-    case content::PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON:
+    case blink::PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON:
       return NotificationActionType::BUTTON;
-    case content::PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT:
+    case blink::PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT:
       return NotificationActionType::TEXT;
   }
 
@@ -95,16 +95,15 @@
 }
 
 // static
-bool EnumTraits<NotificationActionType,
-                content::PlatformNotificationActionType>::
+bool EnumTraits<NotificationActionType, blink::PlatformNotificationActionType>::
     FromMojom(NotificationActionType input,
-              content::PlatformNotificationActionType* out) {
+              blink::PlatformNotificationActionType* out) {
   switch (input) {
     case NotificationActionType::BUTTON:
-      *out = content::PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON;
+      *out = blink::PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON;
       return true;
     case NotificationActionType::TEXT:
-      *out = content::PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT;
+      *out = blink::PLATFORM_NOTIFICATION_ACTION_TYPE_TEXT;
       return true;
   }
 
@@ -113,9 +112,9 @@
 
 // static
 bool StructTraits<blink::mojom::NotificationActionDataView,
-                  content::PlatformNotificationAction>::
+                  blink::PlatformNotificationAction>::
     Read(blink::mojom::NotificationActionDataView notification_action,
-         content::PlatformNotificationAction* out) {
+         blink::PlatformNotificationAction* out) {
   base::Optional<base::string16> placeholder;
   if (!notification_action.ReadType(&out->type) ||
       !notification_action.ReadTitle(&out->title) ||
@@ -130,9 +129,9 @@
 
 // static
 bool StructTraits<blink::mojom::NotificationDataDataView,
-                  content::PlatformNotificationData>::
+                  blink::PlatformNotificationData>::
     Read(blink::mojom::NotificationDataDataView notification_data,
-         content::PlatformNotificationData* platform_notification_data) {
+         blink::PlatformNotificationData* platform_notification_data) {
   // TODO(https://crbug.com/798466): Read the data directly into
   // platform_notification_data.data once it stores a vector of ints not chars.
   std::vector<uint8_t> data;
@@ -173,9 +172,9 @@
 
 // static
 bool StructTraits<blink::mojom::NotificationResourcesDataView,
-                  content::NotificationResources>::
+                  blink::NotificationResources>::
     Read(blink::mojom::NotificationResourcesDataView in,
-         content::NotificationResources* out) {
+         blink::NotificationResources* out) {
   return in.ReadImage(&out->image) && in.ReadIcon(&out->notification_icon) &&
          in.ReadBadge(&out->badge) && in.ReadActionIcons(&out->action_icons);
 }
diff --git a/content/common/notifications/notification_struct_traits_unittest.cc b/third_party/blink/common/notifications/notification_struct_traits_unittest.cc
similarity index 95%
rename from content/common/notifications/notification_struct_traits_unittest.cc
rename to third_party/blink/common/notifications/notification_struct_traits_unittest.cc
index aca9fb5..6327a13 100644
--- a/content/common/notifications/notification_struct_traits_unittest.cc
+++ b/third_party/blink/common/notifications/notification_struct_traits_unittest.cc
@@ -2,20 +2,21 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/common/notifications/notification_struct_traits.h"
+#include "third_party/blink/public/common/notifications/notification_struct_traits.h"
 
 #include "base/macros.h"
+#include "base/stl_util.h"
 #include "base/strings/stringprintf.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
-#include "content/public/common/platform_notification_data.h"
 #include "mojo/public/cpp/test_support/test_utils.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/platform/modules/notifications/notification.mojom.h"
+#include "third_party/blink/public/common/notifications/platform_notification_data.h"
+#include "third_party/blink/public/mojom/notifications/notification.mojom.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "url/gurl.h"
 
-namespace content {
+namespace blink {
 
 namespace {
 
@@ -49,7 +50,7 @@
 
   const int vibration_pattern[] = {500, 100, 30};
   notification_data.vibration_pattern.assign(
-      vibration_pattern, vibration_pattern + arraysize(vibration_pattern));
+      vibration_pattern, vibration_pattern + base::size(vibration_pattern));
 
   notification_data.timestamp = base::Time::FromJsTime(1513966159000.);
   notification_data.renotify = true;
@@ -57,7 +58,7 @@
   notification_data.require_interaction = true;
 
   const char data[] = "mock binary notification data";
-  notification_data.data.assign(data, data + arraysize(data));
+  notification_data.data.assign(data, data + base::size(data));
 
   notification_data.actions.resize(2);
   notification_data.actions[0].type = PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON;
@@ -247,4 +248,4 @@
   }
 }
 
-}  // namespace content
+}  // namespace blink
diff --git a/content/public/common/platform_notification_data.cc b/third_party/blink/common/notifications/platform_notification_data.cc
similarity index 82%
rename from content/public/common/platform_notification_data.cc
rename to third_party/blink/common/notifications/platform_notification_data.cc
index 904015a..8de726b 100644
--- a/content/public/common/platform_notification_data.cc
+++ b/third_party/blink/common/notifications/platform_notification_data.cc
@@ -2,9 +2,9 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "content/public/common/platform_notification_data.h"
+#include "third_party/blink/public/common/notifications/platform_notification_data.h"
 
-namespace content {
+namespace blink {
 
 PlatformNotificationAction::PlatformNotificationAction() {}
 
@@ -20,4 +20,4 @@
 
 PlatformNotificationData::~PlatformNotificationData() {}
 
-}  // namespace content
+}  // namespace blink
diff --git a/third_party/blink/common/test/run_all_unittests.cc b/third_party/blink/common/test/run_all_unittests.cc
index aaa1df0..0adefa8 100644
--- a/third_party/blink/common/test/run_all_unittests.cc
+++ b/third_party/blink/common/test/run_all_unittests.cc
@@ -8,12 +8,14 @@
 
 #include "base/bind.h"
 #include "base/test/test_suite.h"
+#include "mojo/core/embedder/embedder.h"
 #include "v8/include/libplatform/libplatform.h"
 #include "v8/include/v8.h"
 
 int main(int argc, char** argv) {
   base::TestSuite test_suite(argc, argv);
 
+  mojo::core::Init();
   v8::V8::InitializeICUDefaultLocation(argv[0]);
   v8::V8::InitializeExternalStartupData(argv[0]);
   auto platform = base::WrapUnique(v8::platform::CreateDefaultPlatform());
diff --git a/third_party/blink/common/typemaps.gni b/third_party/blink/common/typemaps.gni
index 27ef35df..b46c007d 100644
--- a/third_party/blink/common/typemaps.gni
+++ b/third_party/blink/common/typemaps.gni
@@ -4,6 +4,6 @@
 
 typemaps = [
   "//third_party/blink/common/feature_policy/feature_policy.typemap",
-  "//third_party/blink/common/message_port/cloneable_message.typemap",
-  "//third_party/blink/common/message_port/transferable_message.typemap",
+  "//third_party/blink/common/messaging/cloneable_message.typemap",
+  "//third_party/blink/common/messaging/transferable_message.typemap",
 ]
diff --git a/third_party/blink/public/BUILD.gn b/third_party/blink/public/BUILD.gn
index 18ab369..24d20ab 100644
--- a/third_party/blink/public/BUILD.gn
+++ b/third_party/blink/public/BUILD.gn
@@ -123,7 +123,7 @@
     "platform/file_path_conversion.h",
     "platform/interface_provider.h",
     "platform/interface_registry.h",
-    "platform/linux/web_fallback_font.h",
+    "platform/linux/out_of_process_font.h",
     "platform/linux/web_sandbox_support.h",
     "platform/mac/web_sandbox_support.h",
     "platform/mac/web_scrollbar_theme.h",
@@ -703,7 +703,6 @@
     "platform/modules/insecure_input/insecure_input_service.mojom",
     "platform/modules/keyboard_lock/keyboard_lock.mojom",
     "platform/modules/locks/lock_manager.mojom",
-    "platform/modules/notifications/notification.mojom",
     "platform/modules/notifications/notification_service.mojom",
     "platform/modules/permissions/permission.mojom",
     "platform/modules/permissions/permission_status.mojom",
diff --git a/third_party/blink/public/common/BUILD.gn b/third_party/blink/public/common/BUILD.gn
index 995656b..708efae 100644
--- a/third_party/blink/public/common/BUILD.gn
+++ b/third_party/blink/public/common/BUILD.gn
@@ -56,11 +56,14 @@
     "manifest/manifest.h",
     "manifest/manifest_icon_selector.h",
     "manifest/web_display_mode.h",
-    "message_port/cloneable_message.h",
-    "message_port/message_port_channel.h",
-    "message_port/string_message_codec.h",
-    "message_port/transferable_message.h",
+    "messaging/cloneable_message.h",
+    "messaging/message_port_channel.h",
+    "messaging/string_message_codec.h",
+    "messaging/transferable_message.h",
     "mime_util/mime_util.h",
+    "notifications/notification_resources.h",
+    "notifications/notification_struct_traits.h",
+    "notifications/platform_notification_data.h",
     "oom_intervention/oom_intervention_types.h",
     "origin_policy/origin_policy.h",
     "origin_trials/origin_trial_policy.h",
diff --git a/third_party/blink/public/common/DEPS b/third_party/blink/public/common/DEPS
index ef1ec1b..5254372 100644
--- a/third_party/blink/public/common/DEPS
+++ b/third_party/blink/public/common/DEPS
@@ -10,6 +10,7 @@
     "+build",
     "+net",
     "+mojo",
+    "+skia/public/interfaces",
     "+third_party/blink/public/common",
     "+third_party/blink/public/mojom",
     "+ui/gfx/geometry",
diff --git a/third_party/blink/public/common/message_port/OWNERS b/third_party/blink/public/common/messaging/OWNERS
similarity index 100%
rename from third_party/blink/public/common/message_port/OWNERS
rename to third_party/blink/public/common/messaging/OWNERS
diff --git a/third_party/blink/public/common/message_port/cloneable_message.h b/third_party/blink/public/common/messaging/cloneable_message.h
similarity index 91%
rename from third_party/blink/public/common/message_port/cloneable_message.h
rename to third_party/blink/public/common/messaging/cloneable_message.h
index 8f6d3fc..81f93d30 100644
--- a/third_party/blink/public/common/message_port/cloneable_message.h
+++ b/third_party/blink/public/common/messaging/cloneable_message.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGE_PORT_CLONEABLE_MESSAGE_H_
-#define THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGE_PORT_CLONEABLE_MESSAGE_H_
+#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGING_CLONEABLE_MESSAGE_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGING_CLONEABLE_MESSAGE_H_
 
 #include <vector>
 
@@ -60,4 +60,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGE_PORT_CLONEABLE_MESSAGE_H_
+#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGING_CLONEABLE_MESSAGE_H_
diff --git a/third_party/blink/public/common/message_port/message_port_channel.h b/third_party/blink/public/common/messaging/message_port_channel.h
similarity index 90%
rename from third_party/blink/public/common/message_port/message_port_channel.h
rename to third_party/blink/public/common/messaging/message_port_channel.h
index fc5c9111..4a09ab3f 100644
--- a/third_party/blink/public/common/message_port/message_port_channel.h
+++ b/third_party/blink/public/common/messaging/message_port_channel.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGE_PORT_MESSAGE_PORT_CHANNEL_H_
-#define THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGE_PORT_MESSAGE_PORT_CHANNEL_H_
+#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGING_MESSAGE_PORT_CHANNEL_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGING_MESSAGE_PORT_CHANNEL_H_
 
 #include <vector>
 
@@ -64,4 +64,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGE_PORT_MESSAGE_PORT_CHANNEL_H_
+#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGING_MESSAGE_PORT_CHANNEL_H_
diff --git a/third_party/blink/public/common/message_port/string_message_codec.h b/third_party/blink/public/common/messaging/string_message_codec.h
similarity index 84%
rename from third_party/blink/public/common/message_port/string_message_codec.h
rename to third_party/blink/public/common/messaging/string_message_codec.h
index 98a6615e..b052d5e8 100644
--- a/third_party/blink/public/common/message_port/string_message_codec.h
+++ b/third_party/blink/public/common/messaging/string_message_codec.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGE_PORT_STRING_MESSAGE_CODEC_H_
-#define THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGE_PORT_STRING_MESSAGE_CODEC_H_
+#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGING_STRING_MESSAGE_CODEC_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGING_STRING_MESSAGE_CODEC_H_
 
 #include <vector>
 #include "base/strings/string16.h"
@@ -30,4 +30,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGE_PORT_STRING_MESSAGE_CODEC_H_
+#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGING_STRING_MESSAGE_CODEC_H_
diff --git a/third_party/blink/public/common/message_port/transferable_message.h b/third_party/blink/public/common/messaging/transferable_message.h
similarity index 76%
rename from third_party/blink/public/common/message_port/transferable_message.h
rename to third_party/blink/public/common/messaging/transferable_message.h
index 7ddd36b7..5f250c0 100644
--- a/third_party/blink/public/common/message_port/transferable_message.h
+++ b/third_party/blink/public/common/messaging/transferable_message.h
@@ -2,18 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGE_PORT_TRANSFERABLE_MESSAGE_H_
-#define THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGE_PORT_TRANSFERABLE_MESSAGE_H_
+#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGING_TRANSFERABLE_MESSAGE_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGING_TRANSFERABLE_MESSAGE_H_
 
 #include <vector>
 
 #include "base/containers/span.h"
 #include "base/macros.h"
 #include "third_party/blink/common/common_export.h"
-#include "third_party/blink/public/common/message_port/cloneable_message.h"
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
+#include "third_party/blink/public/common/messaging/cloneable_message.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
 #include "third_party/blink/public/mojom/array_buffer/array_buffer_contents.mojom.h"
-#include "third_party/blink/public/mojom/message_port/user_activation_snapshot.mojom.h"
+#include "third_party/blink/public/mojom/messaging/user_activation_snapshot.mojom.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
 namespace blink {
@@ -47,4 +47,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGE_PORT_TRANSFERABLE_MESSAGE_H_
+#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_MESSAGING_TRANSFERABLE_MESSAGE_H_
diff --git a/content/common/notifications/OWNERS b/third_party/blink/public/common/notifications/OWNERS
similarity index 100%
copy from content/common/notifications/OWNERS
copy to third_party/blink/public/common/notifications/OWNERS
diff --git a/content/public/common/notification_resources.h b/third_party/blink/public/common/notifications/notification_resources.h
similarity index 73%
rename from content/public/common/notification_resources.h
rename to third_party/blink/public/common/notifications/notification_resources.h
index e8c56a5..6f6b71b 100644
--- a/content/public/common/notification_resources.h
+++ b/third_party/blink/public/common/notifications/notification_resources.h
@@ -2,18 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_PUBLIC_COMMON_NOTIFICATION_RESOURCES_H_
-#define CONTENT_PUBLIC_COMMON_NOTIFICATION_RESOURCES_H_
+#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_NOTIFICATIONS_NOTIFICATION_RESOURCES_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_NOTIFICATIONS_NOTIFICATION_RESOURCES_H_
 
 #include <vector>
 
-#include "content/common/content_export.h"
+#include "third_party/blink/common/common_export.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
-namespace content {
+namespace blink {
 
 // Structure to hold the resources associated with a Web Notification.
-struct CONTENT_EXPORT NotificationResources {
+struct BLINK_COMMON_EXPORT NotificationResources {
   NotificationResources();
   NotificationResources(const NotificationResources& other);
   ~NotificationResources();
@@ -35,6 +35,6 @@
   std::vector<SkBitmap> action_icons;
 };
 
-}  // namespace content
+}  // namespace blink
 
-#endif  // CONTENT_PUBLIC_COMMON_NOTIFICATION_RESOURCES_H_
+#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_NOTIFICATIONS_NOTIFICATION_RESOURCES_H_
diff --git a/third_party/blink/public/common/notifications/notification_struct_traits.h b/third_party/blink/public/common/notifications/notification_struct_traits.h
new file mode 100644
index 0000000..d642c87a
--- /dev/null
+++ b/third_party/blink/public/common/notifications/notification_struct_traits.h
@@ -0,0 +1,180 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_NOTIFICATIONS_NOTIFICATION_STRUCT_TRAITS_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_NOTIFICATIONS_NOTIFICATION_STRUCT_TRAITS_H_
+
+#include "base/containers/span.h"
+#include "base/strings/string16.h"
+#include "mojo/public/cpp/base/string16_mojom_traits.h"
+#include "mojo/public/cpp/bindings/struct_traits.h"
+#include "skia/public/interfaces/bitmap_skbitmap_struct_traits.h"
+#include "third_party/blink/common/common_export.h"
+#include "third_party/blink/public/common/notifications/platform_notification_data.h"
+#include "third_party/blink/public/mojom/notifications/notification.mojom.h"
+#include "url/gurl.h"
+#include "url/mojom/url_gurl_mojom_traits.h"
+
+namespace mojo {
+
+template <>
+struct BLINK_COMMON_EXPORT
+    EnumTraits<blink::mojom::NotificationDirection,
+               blink::PlatformNotificationData::Direction> {
+  static blink::mojom::NotificationDirection ToMojom(
+      blink::PlatformNotificationData::Direction input);
+
+  static bool FromMojom(blink::mojom::NotificationDirection input,
+                        blink::PlatformNotificationData::Direction* out);
+};
+
+template <>
+struct BLINK_COMMON_EXPORT EnumTraits<blink::mojom::NotificationActionType,
+                                      blink::PlatformNotificationActionType> {
+  static blink::mojom::NotificationActionType ToMojom(
+      blink::PlatformNotificationActionType input);
+
+  static bool FromMojom(blink::mojom::NotificationActionType input,
+                        blink::PlatformNotificationActionType* out);
+};
+
+template <>
+struct BLINK_COMMON_EXPORT
+    StructTraits<blink::mojom::NotificationActionDataView,
+                 blink::PlatformNotificationAction> {
+  static blink::PlatformNotificationActionType type(
+      const blink::PlatformNotificationAction& action) {
+    return action.type;
+  }
+
+  static const std::string& action(
+      const blink::PlatformNotificationAction& action) {
+    return action.action;
+  }
+
+  static const base::string16& title(
+      const blink::PlatformNotificationAction& action) {
+    return action.title;
+  }
+
+  static const GURL& icon(const blink::PlatformNotificationAction& action) {
+    return action.icon;
+  }
+
+  static const base::Optional<base::string16>& placeholder(
+      const blink::PlatformNotificationAction& action) {
+    return action.placeholder.as_optional_string16();
+  }
+
+  static bool Read(
+      blink::mojom::NotificationActionDataView notification_action,
+      blink::PlatformNotificationAction* platform_notification_action);
+};
+
+template <>
+struct BLINK_COMMON_EXPORT StructTraits<blink::mojom::NotificationDataDataView,
+                                        blink::PlatformNotificationData> {
+  static const base::string16& title(
+      const blink::PlatformNotificationData& data) {
+    return data.title;
+  }
+
+  static blink::PlatformNotificationData::Direction direction(
+      const blink::PlatformNotificationData& data) {
+    return data.direction;
+  }
+
+  static const std::string& lang(const blink::PlatformNotificationData& data) {
+    return data.lang;
+  }
+
+  static const base::string16& body(
+      const blink::PlatformNotificationData& data) {
+    return data.body;
+  }
+
+  static const std::string& tag(const blink::PlatformNotificationData& data) {
+    return data.tag;
+  }
+
+  static const GURL& image(const blink::PlatformNotificationData& data) {
+    return data.image;
+  }
+
+  static const GURL& icon(const blink::PlatformNotificationData& data) {
+    return data.icon;
+  }
+
+  static const GURL& badge(const blink::PlatformNotificationData& data) {
+    return data.badge;
+  }
+
+  static const base::span<const int32_t> vibration_pattern(
+      const blink::PlatformNotificationData& data) {
+    // TODO(https://crbug.com/798466): Store as int32s to avoid this cast.
+    return base::make_span(
+        reinterpret_cast<const int32_t*>(data.vibration_pattern.data()),
+        data.vibration_pattern.size());
+  }
+
+  static double timestamp(const blink::PlatformNotificationData& data) {
+    return data.timestamp.ToJsTime();
+  }
+
+  static bool renotify(const blink::PlatformNotificationData& data) {
+    return data.renotify;
+  }
+
+  static bool silent(const blink::PlatformNotificationData& data) {
+    return data.silent;
+  }
+
+  static bool require_interaction(const blink::PlatformNotificationData& data) {
+    return data.require_interaction;
+  }
+
+  static const base::span<const uint8_t> data(
+      const blink::PlatformNotificationData& data) {
+    // TODO(https://crbug.com/798466): Align data types to avoid this cast.
+    return base::make_span(reinterpret_cast<const uint8_t*>(data.data.data()),
+                           data.data.size());
+  }
+
+  static const std::vector<blink::PlatformNotificationAction>& actions(
+      const blink::PlatformNotificationData& data) {
+    return data.actions;
+  }
+
+  static bool Read(blink::mojom::NotificationDataDataView notification_data,
+                   blink::PlatformNotificationData* platform_notification_data);
+};
+
+template <>
+struct BLINK_COMMON_EXPORT
+    StructTraits<blink::mojom::NotificationResourcesDataView,
+                 blink::NotificationResources> {
+  static const SkBitmap& image(const blink::NotificationResources& resources) {
+    return resources.image;
+  }
+
+  static const SkBitmap& icon(const blink::NotificationResources& resources) {
+    return resources.notification_icon;
+  }
+
+  static const SkBitmap& badge(const blink::NotificationResources& resources) {
+    return resources.badge;
+  }
+
+  static const std::vector<SkBitmap>& action_icons(
+      const blink::NotificationResources& resources) {
+    return resources.action_icons;
+  }
+
+  static bool Read(blink::mojom::NotificationResourcesDataView in,
+                   blink::NotificationResources* out);
+};
+
+}  // namespace mojo
+
+#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_NOTIFICATIONS_NOTIFICATION_STRUCT_TRAITS_H_
diff --git a/third_party/blink/public/common/notifications/notification_types.typemap b/third_party/blink/public/common/notifications/notification_types.typemap
new file mode 100644
index 0000000..0910c23
--- /dev/null
+++ b/third_party/blink/public/common/notifications/notification_types.typemap
@@ -0,0 +1,18 @@
+# Copyright 2017 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+mojom = "//third_party/blink/public/mojom/notifications/notification.mojom"
+public_headers = [
+  "//third_party/blink/public/common/notifications/notification_resources.h",
+  "//third_party/blink/public/common/notifications/platform_notification_data.h",
+]
+traits_headers = [ "//third_party/blink/public/common/notifications/notification_struct_traits.h" ]
+deps = [
+  "//mojo/public/cpp/bindings",
+]
+type_mappings = [
+  "blink.mojom.NotificationData=blink::PlatformNotificationData",
+  "blink.mojom.NotificationDirection=blink::PlatformNotificationData::Direction",
+  "blink.mojom.NotificationResources=blink::NotificationResources",
+]
diff --git a/content/public/common/platform_notification_data.h b/third_party/blink/public/common/notifications/platform_notification_data.h
similarity index 88%
rename from content/public/common/platform_notification_data.h
rename to third_party/blink/public/common/notifications/platform_notification_data.h
index c6bd563..c6131b2 100644
--- a/content/public/common/platform_notification_data.h
+++ b/third_party/blink/public/common/notifications/platform_notification_data.h
@@ -2,10 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_PUBLIC_COMMON_PLATFORM_NOTIFICATION_DATA_H_
-#define CONTENT_PUBLIC_COMMON_PLATFORM_NOTIFICATION_DATA_H_
-
-#include <stddef.h>
+#ifndef THIRD_PARTY_BLINK_PUBLIC_COMMON_NOTIFICATIONS_PLATFORM_NOTIFICATION_DATA_H_
+#define THIRD_PARTY_BLINK_PUBLIC_COMMON_NOTIFICATIONS_PLATFORM_NOTIFICATION_DATA_H_
 
 #include <string>
 #include <vector>
@@ -13,10 +11,10 @@
 #include "base/strings/nullable_string16.h"
 #include "base/strings/string16.h"
 #include "base/time/time.h"
-#include "content/common/content_export.h"
+#include "third_party/blink/common/common_export.h"
 #include "url/gurl.h"
 
-namespace content {
+namespace blink {
 
 enum PlatformNotificationActionType {
   PLATFORM_NOTIFICATION_ACTION_TYPE_BUTTON = 0,
@@ -25,7 +23,7 @@
 
 // A notification action (button or text input); corresponds to Blink
 // WebNotificationAction.
-struct CONTENT_EXPORT PlatformNotificationAction {
+struct BLINK_COMMON_EXPORT PlatformNotificationAction {
   PlatformNotificationAction();
   PlatformNotificationAction(const PlatformNotificationAction& other);
   ~PlatformNotificationAction();
@@ -51,7 +49,7 @@
 // Structure representing the information associated with a Web Notification.
 // This struct should include the developer-visible information, kept
 // synchronized with the WebNotificationData structure defined in the Blink API.
-struct CONTENT_EXPORT PlatformNotificationData {
+struct BLINK_COMMON_EXPORT PlatformNotificationData {
   PlatformNotificationData();
   PlatformNotificationData(const PlatformNotificationData& other);
   ~PlatformNotificationData();
@@ -118,6 +116,6 @@
   std::vector<PlatformNotificationAction> actions;
 };
 
-}  // namespace content
+}  // namespace blink
 
-#endif  // CONTENT_PUBLIC_COMMON_PLATFORM_NOTIFICATION_DATA_H_
+#endif  // THIRD_PARTY_BLINK_PUBLIC_COMMON_NOTIFICATIONS_PLATFORM_NOTIFICATION_DATA_H_
diff --git a/third_party/blink/public/mojom/BUILD.gn b/third_party/blink/public/mojom/BUILD.gn
index af2b5f63..84eccc7 100644
--- a/third_party/blink/public/mojom/BUILD.gn
+++ b/third_party/blink/public/mojom/BUILD.gn
@@ -38,6 +38,7 @@
     "manifest/manifest.mojom",
     "manifest/manifest_manager.mojom",
     "net/ip_address_space.mojom",
+    "notifications/notification.mojom",
     "page/display_cutout.mojom",
     "page/page_visibility_state.mojom",
     "payments/payment_app.mojom",
@@ -134,8 +135,8 @@
 # those high-level service worker mojom files there.
 mojom("mojom_core") {
   sources = [
-    "message_port/message_port.mojom",
-    "message_port/user_activation_snapshot.mojom",
+    "messaging/message_port.mojom",
+    "messaging/user_activation_snapshot.mojom",
     "portal/portal.mojom",
     "service_worker/service_worker.mojom",
     "service_worker/service_worker_object.mojom",
diff --git a/third_party/blink/public/mojom/message_port/OWNERS b/third_party/blink/public/mojom/messaging/OWNERS
similarity index 100%
rename from third_party/blink/public/mojom/message_port/OWNERS
rename to third_party/blink/public/mojom/messaging/OWNERS
diff --git a/third_party/blink/public/mojom/message_port/message_port.mojom b/third_party/blink/public/mojom/messaging/message_port.mojom
similarity index 96%
rename from third_party/blink/public/mojom/message_port/message_port.mojom
rename to third_party/blink/public/mojom/messaging/message_port.mojom
index fad68a35..f030eab 100644
--- a/third_party/blink/public/mojom/message_port/message_port.mojom
+++ b/third_party/blink/public/mojom/messaging/message_port.mojom
@@ -8,7 +8,7 @@
 import "mojo/public/mojom/base/unguessable_token.mojom";
 import "third_party/blink/public/mojom/array_buffer/array_buffer_contents.mojom";
 import "third_party/blink/public/mojom/blob/serialized_blob.mojom";
-import "third_party/blink/public/mojom/message_port/user_activation_snapshot.mojom";
+import "third_party/blink/public/mojom/messaging/user_activation_snapshot.mojom";
 import "skia/public/interfaces/bitmap.mojom";
 
 // A MessagePort is represented as a raw mojo message pipe, as such no interface
diff --git a/third_party/blink/public/mojom/message_port/user_activation_snapshot.mojom b/third_party/blink/public/mojom/messaging/user_activation_snapshot.mojom
similarity index 100%
rename from third_party/blink/public/mojom/message_port/user_activation_snapshot.mojom
rename to third_party/blink/public/mojom/messaging/user_activation_snapshot.mojom
diff --git a/third_party/blink/public/mojom/notifications/OWNERS b/third_party/blink/public/mojom/notifications/OWNERS
new file mode 100644
index 0000000..0a5fdca
--- /dev/null
+++ b/third_party/blink/public/mojom/notifications/OWNERS
@@ -0,0 +1,7 @@
+peter@chromium.org
+
+per-file *.mojom=set noparent
+per-file *.mojom=file://ipc/SECURITY_OWNERS
+
+# TEAM: platform-capabilities@chromium.org
+# COMPONENT: UI>Notifications
diff --git a/third_party/blink/public/platform/modules/notifications/notification.mojom b/third_party/blink/public/mojom/notifications/notification.mojom
similarity index 100%
rename from third_party/blink/public/platform/modules/notifications/notification.mojom
rename to third_party/blink/public/mojom/notifications/notification.mojom
diff --git a/third_party/blink/public/mojom/service_worker/service_worker.mojom b/third_party/blink/public/mojom/service_worker/service_worker.mojom
index d3bb12e..096cb24 100644
--- a/third_party/blink/public/mojom/service_worker/service_worker.mojom
+++ b/third_party/blink/public/mojom/service_worker/service_worker.mojom
@@ -4,7 +4,7 @@
 
 module blink.mojom;
 
-import "third_party/blink/public/mojom/message_port/message_port.mojom";
+import "third_party/blink/public/mojom/messaging/message_port.mojom";
 import "third_party/blink/public/mojom/service_worker/service_worker_error_type.mojom";
 import "third_party/blink/public/mojom/service_worker/service_worker_client.mojom";
 import "url/mojom/url.mojom";
diff --git a/third_party/blink/public/mojom/service_worker/service_worker_object.mojom b/third_party/blink/public/mojom/service_worker/service_worker_object.mojom
index 79c3393..2645595 100644
--- a/third_party/blink/public/mojom/service_worker/service_worker_object.mojom
+++ b/third_party/blink/public/mojom/service_worker/service_worker_object.mojom
@@ -4,7 +4,7 @@
 
 module blink.mojom;
 
-import "third_party/blink/public/mojom/message_port/message_port.mojom";
+import "third_party/blink/public/mojom/messaging/message_port.mojom";
 import "third_party/blink/public/mojom/service_worker/service_worker_state.mojom";
 import "url/mojom/url.mojom";
 
diff --git a/third_party/blink/public/platform/linux/web_fallback_font.h b/third_party/blink/public/platform/linux/out_of_process_font.h
similarity index 88%
rename from third_party/blink/public/platform/linux/web_fallback_font.h
rename to third_party/blink/public/platform/linux/out_of_process_font.h
index dc60320..3f60890 100644
--- a/third_party/blink/public/platform/linux/web_fallback_font.h
+++ b/third_party/blink/public/platform/linux/out_of_process_font.h
@@ -28,8 +28,8 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_LINUX_WEB_FALLBACK_FONT_H_
-#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_LINUX_WEB_FALLBACK_FONT_H_
+#ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_LINUX_OUT_OF_PROCESS_FONT_H_
+#define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_LINUX_OUT_OF_PROCESS_FONT_H_
 
 #include "third_party/blink/public/platform/web_common.h"
 #include "third_party/blink/public/platform/web_string.h"
@@ -37,8 +37,8 @@
 
 namespace blink {
 
-struct WebFallbackFont {
-  WebFallbackFont()
+struct OutOfProcessFont {
+  OutOfProcessFont()
       : name(WebString()),
         filename(WebVector<char>()),
         fontconfig_interface_id(0),
@@ -55,4 +55,4 @@
 
 }  // namespace blink
 
-#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_LINUX_WEB_FALLBACK_FONT_H_
+#endif  // THIRD_PARTY_BLINK_PUBLIC_PLATFORM_LINUX_OUT_OF_PROCESS_FONT_H_
diff --git a/third_party/blink/public/platform/linux/web_sandbox_support.h b/third_party/blink/public/platform/linux/web_sandbox_support.h
index 1c4b6590..86628fdb 100644
--- a/third_party/blink/public/platform/linux/web_sandbox_support.h
+++ b/third_party/blink/public/platform/linux/web_sandbox_support.h
@@ -31,7 +31,7 @@
 #ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_LINUX_WEB_SANDBOX_SUPPORT_H_
 #define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_LINUX_WEB_SANDBOX_SUPPORT_H_
 
-#include "third_party/blink/public/platform/linux/web_fallback_font.h"
+#include "third_party/blink/public/platform/linux/out_of_process_font.h"
 #include "third_party/blink/public/platform/web_common.h"
 #include "third_party/blink/public/platform/web_string.h"
 
@@ -52,11 +52,11 @@
   //   preferredLocale: preferred locale identifier for the |characters|
   //                    (e.g. "en", "ja", "zh-CN")
   //
-  // Returns a WebFallbackFont instance with the font name and filename.
+  // Returns a OutOfProcessFont instance with the font name and filename.
   // The instance has empty font name if the request cannot be satisfied.
   virtual void GetFallbackFontForCharacter(WebUChar32,
                                            const char* preferred_locale,
-                                           WebFallbackFont*) = 0;
+                                           OutOfProcessFont*) = 0;
 
   // Fill out the given WebFontRenderStyle with the user's preferences for
   // rendering the given font at the given size (in pixels), given weight and
diff --git a/third_party/blink/public/platform/modules/broadcastchannel/broadcast_channel.mojom b/third_party/blink/public/platform/modules/broadcastchannel/broadcast_channel.mojom
index 145a7740..b37834d3 100644
--- a/third_party/blink/public/platform/modules/broadcastchannel/broadcast_channel.mojom
+++ b/third_party/blink/public/platform/modules/broadcastchannel/broadcast_channel.mojom
@@ -4,7 +4,7 @@
 
 module blink.mojom;
 
-import "third_party/blink/public/mojom/message_port/message_port.mojom";
+import "third_party/blink/public/mojom/messaging/message_port.mojom";
 import "url/mojom/origin.mojom";
 
 // A pair of BroadcastChannelClient interfaces is used to represent a connection
diff --git a/third_party/blink/public/platform/modules/notifications/notification_service.mojom b/third_party/blink/public/platform/modules/notifications/notification_service.mojom
index 75f290c..43a51bb 100644
--- a/third_party/blink/public/platform/modules/notifications/notification_service.mojom
+++ b/third_party/blink/public/platform/modules/notifications/notification_service.mojom
@@ -4,7 +4,7 @@
 
 module blink.mojom;
 
-import "third_party/blink/public/platform/modules/notifications/notification.mojom";
+import "third_party/blink/public/mojom/notifications/notification.mojom";
 import "third_party/blink/public/platform/modules/permissions/permission_status.mojom";
 
 // Interface for receiving events relating to non-persistent notifications.
diff --git a/third_party/blink/public/platform/modules/service_worker/web_service_worker.h b/third_party/blink/public/platform/modules/service_worker/web_service_worker.h
index a4c241e..6ae9207 100644
--- a/third_party/blink/public/platform/modules/service_worker/web_service_worker.h
+++ b/third_party/blink/public/platform/modules/service_worker/web_service_worker.h
@@ -31,7 +31,7 @@
 #ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_H_
 #define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_H_
 
-#include "third_party/blink/public/common/message_port/transferable_message.h"
+#include "third_party/blink/public/common/messaging/transferable_message.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_state.mojom-shared.h"
 #include "third_party/blink/public/platform/web_callbacks.h"
 #include "third_party/blink/public/platform/web_common.h"
diff --git a/third_party/blink/public/platform/modules/service_worker/web_service_worker_provider_client.h b/third_party/blink/public/platform/modules/service_worker/web_service_worker_provider_client.h
index 1077221..361ca6f 100644
--- a/third_party/blink/public/platform/modules/service_worker/web_service_worker_provider_client.h
+++ b/third_party/blink/public/platform/modules/service_worker/web_service_worker_provider_client.h
@@ -31,7 +31,7 @@
 #ifndef THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_PROVIDER_CLIENT_H_
 #define THIRD_PARTY_BLINK_PUBLIC_PLATFORM_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_PROVIDER_CLIENT_H_
 
-#include "third_party/blink/public/common/message_port/transferable_message.h"
+#include "third_party/blink/public/common/messaging/transferable_message.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker.h"
 #include "third_party/blink/public/platform/web_common.h"
 #include "third_party/blink/public/platform/web_feature.mojom-shared.h"
diff --git a/third_party/blink/public/platform/web_feature.mojom b/third_party/blink/public/platform/web_feature.mojom
index 9ae79df..1102d3d 100644
--- a/third_party/blink/public/platform/web_feature.mojom
+++ b/third_party/blink/public/platform/web_feature.mojom
@@ -1993,6 +1993,7 @@
   kV8Window_WebkitMediaStream_ConstructorGetter = 2538,
   kTextEncoderStreamConstructor = 2539,
   kTextDecoderStreamConstructor = 2540,
+  kSignedExchangeInnerResponse = 2541,
 
   // 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/public/platform/web_url_response.h b/third_party/blink/public/platform/web_url_response.h
index 75f7cb3..1b15b39 100644
--- a/third_party/blink/public/platform/web_url_response.h
+++ b/third_party/blink/public/platform/web_url_response.h
@@ -286,6 +286,8 @@
   // Original size of the response before decompression.
   BLINK_PLATFORM_EXPORT void SetEncodedDataLength(long long);
 
+  BLINK_PLATFORM_EXPORT void SetIsSignedExchangeInnerResponse(bool);
+
   // Extra data associated with the underlying resource response. Resource
   // responses can be copied. If non-null, each copy of a resource response
   // holds a pointer to the extra data, and the extra data pointer will be
diff --git a/third_party/blink/public/public_typemaps.gni b/third_party/blink/public/public_typemaps.gni
index 7912f689..ba1ef5cc 100644
--- a/third_party/blink/public/public_typemaps.gni
+++ b/third_party/blink/public/public_typemaps.gni
@@ -7,8 +7,9 @@
   "//third_party/blink/public/platform/content_security_policy.typemap",
   "//third_party/blink/public/platform/referrer_policy.typemap",
   "//third_party/blink/public/common/indexeddb/indexeddb.typemap",
-  "//third_party/blink/public/common/screen_orientation/screen_orientation_lock_types.typemap",
   "//third_party/blink/public/common/manifest/display_mode.typemap",
   "//third_party/blink/public/common/manifest/manifest.typemap",
+  "//third_party/blink/public/common/notifications/notification_types.typemap",
+  "//third_party/blink/public/common/screen_orientation/screen_orientation_lock_types.typemap",
   "//third_party/blink/public/web/console_message.typemap",
 ]
diff --git a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
index fddb9e1..397cfe85 100644
--- a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
+++ b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h
@@ -33,7 +33,7 @@
 
 #include <memory>
 
-#include "third_party/blink/public/common/message_port/transferable_message.h"
+#include "third_party/blink/public/common/messaging/transferable_message.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom-shared.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_claim_callbacks.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h"
@@ -102,6 +102,10 @@
   // completed. Called on the main thread.
   virtual void WorkerContextFailedToStart() {}
 
+  // The worker started but it could not execute because loading the
+  // installed script failed.
+  virtual void FailedToLoadInstalledScript() {}
+
   // The worker script successfully loaded. Called on the main thread when the
   // script is served from ResourceLoader or on the worker thread when the
   // script is served via WebServiceWorkerInstalledScriptsManager.
diff --git a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h
index 23b8e55..200a0b07 100644
--- a/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h
+++ b/third_party/blink/public/web/modules/service_worker/web_service_worker_context_proxy.h
@@ -32,7 +32,7 @@
 #define THIRD_PARTY_BLINK_PUBLIC_WEB_MODULES_SERVICE_WORKER_WEB_SERVICE_WORKER_CONTEXT_PROXY_H_
 
 #include "base/time/time.h"
-#include "third_party/blink/public/common/message_port/transferable_message.h"
+#include "third_party/blink/public/common/messaging/transferable_message.h"
 #include "third_party/blink/public/platform/modules/background_fetch/background_fetch.mojom-shared.h"
 #include "third_party/blink/public/platform/modules/background_fetch/web_background_fetch_registration.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker.h"
diff --git a/third_party/blink/public/web/web_dom_message_event.h b/third_party/blink/public/web/web_dom_message_event.h
index 6c6f282..37712fa 100644
--- a/third_party/blink/public/web/web_dom_message_event.h
+++ b/third_party/blink/public/web/web_dom_message_event.h
@@ -30,8 +30,8 @@
 #ifndef THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_DOM_MESSAGE_EVENT_H_
 #define THIRD_PARTY_BLINK_PUBLIC_WEB_WEB_DOM_MESSAGE_EVENT_H_
 
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
-#include "third_party/blink/public/common/message_port/transferable_message.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
+#include "third_party/blink/public/common/messaging/transferable_message.h"
 #include "third_party/blink/public/platform/web_string.h"
 #include "third_party/blink/public/web/web_document.h"
 #include "third_party/blink/public/web/web_dom_event.h"
diff --git a/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt b/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt
index 980ae47..20f1d2b 100644
--- a/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt
+++ b/third_party/blink/renderer/bindings/IDLExtendedAttributes.txt
@@ -98,6 +98,7 @@
 SaveSameObject
 SecureContext=|*
 SetterCallWith=ExecutionContext|ScriptArguments|CurrentWindow|EnteredWindow
+TreatNonObjectAsNull
 TreatNullAs=NullString|EmptyString
 URL
 Unforgeable
diff --git a/third_party/blink/renderer/bindings/core/v8/custom/v8_window_custom.cc b/third_party/blink/renderer/bindings/core/v8/custom/v8_window_custom.cc
index 61a3918..cb3a09f 100644
--- a/third_party/blink/renderer/bindings/core/v8/custom/v8_window_custom.cc
+++ b/third_party/blink/renderer/bindings/core/v8/custom/v8_window_custom.cc
@@ -35,7 +35,6 @@
 #include "third_party/blink/renderer/bindings/core/v8/script_source_code.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_event.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_event_listener_or_event_handler.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_html_collection.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_node.h"
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
diff --git a/third_party/blink/renderer/bindings/core/v8/serialization/post_message_helper.h b/third_party/blink/renderer/bindings/core/v8/serialization/post_message_helper.h
index 4adfc46..b426b8957 100644
--- a/third_party/blink/renderer/bindings/core/v8/serialization/post_message_helper.h
+++ b/third_party/blink/renderer/bindings/core/v8/serialization/post_message_helper.h
@@ -6,7 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_BINDINGS_CORE_V8_SERIALIZATION_POST_MESSAGE_HELPER_H_
 
 #include "base/memory/scoped_refptr.h"
-#include "third_party/blink/public/mojom/message_port/message_port.mojom-blink.h"
+#include "third_party/blink/public/mojom/messaging/message_port.mojom-blink.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/platform/wtf/allocator.h"
 #include "v8/include/v8.h"
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc b/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc
index 051708e..4da1387 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.cc
@@ -34,7 +34,6 @@
 #include "third_party/blink/renderer/bindings/core/v8/idl_types.h"
 #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_controller.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_abstract_event_handler.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_array_buffer_view.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_element.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_event_target.h"
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_event_listener_helper.cc b/third_party/blink/renderer/bindings/core/v8/v8_event_listener_helper.cc
index 5162578c..e9208db 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_event_listener_helper.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_event_listener_helper.cc
@@ -74,10 +74,8 @@
   v8::Isolate* isolate = script_state->GetIsolate();
   V8PrivateProperty::Symbol listener_property =
       is_attribute
-          ? V8PrivateProperty::
-                GetV8EventListenerOrEventHandlerAttributeListener(isolate)
-          : V8PrivateProperty::GetV8EventListenerOrEventHandlerListener(
-                isolate);
+          ? V8PrivateProperty::GetCustomWrappableEventHandler(isolate)
+          : V8PrivateProperty::GetCustomWrappableEventListener(isolate);
 
   return GetEventListenerInternal<EventListener>(
       script_state, object, listener_property, lookup,
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc b/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc
index 561e73c..18603ac 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_gc_controller.cc
@@ -38,7 +38,6 @@
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_source_code.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_abstract_event_handler.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_node.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_script_runner.h"
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_lazy_event_listener.cc b/third_party/blink/renderer/bindings/core/v8/v8_lazy_event_listener.cc
index 377df4d..b36ccd6 100644
--- a/third_party/blink/renderer/bindings/core/v8/v8_lazy_event_listener.cc
+++ b/third_party/blink/renderer/bindings/core/v8/v8_lazy_event_listener.cc
@@ -204,9 +204,9 @@
 
   wrapped_function->SetName(V8String(GetIsolate(), function_name_));
 
-  SetListenerObject(script_state, wrapped_function,
-                    V8PrivateProperty::GetV8EventListenerOrEventHandlerListener(
-                        GetIsolate()));
+  SetListenerObject(
+      script_state, wrapped_function,
+      V8PrivateProperty::GetCustomWrappableEventListener(GetIsolate()));
 }
 
 void V8LazyEventListener::FireErrorEvent(v8::Local<v8::Context> v8_context,
diff --git a/third_party/blink/renderer/bindings/scripts/v8_callback_function.py b/third_party/blink/renderer/bindings/scripts/v8_callback_function.py
index 3e9827f..8ca9fb6 100644
--- a/third_party/blink/renderer/bindings/scripts/v8_callback_function.py
+++ b/third_party/blink/renderer/bindings/scripts/v8_callback_function.py
@@ -46,6 +46,7 @@
         'forward_declarations': sorted(forward_declarations(callback_function)),
         'header_includes': sorted(CALLBACK_FUNCTION_H_INCLUDES),
         'idl_type': idl_type_str,
+        'is_treat_non_object_as_null': 'TreatNonObjectAsNull' in callback_function.extended_attributes,
         'native_value_traits_tag': v8_types.idl_type_to_native_value_traits_tag(idl_type),
         'return_cpp_type': idl_type.cpp_type,
     }
diff --git a/third_party/blink/renderer/bindings/templates/callback_function.cpp.tmpl b/third_party/blink/renderer/bindings/templates/callback_function.cpp.tmpl
index a32046bf..f846c67b 100644
--- a/third_party/blink/renderer/bindings/templates/callback_function.cpp.tmpl
+++ b/third_party/blink/renderer/bindings/templates/callback_function.cpp.tmpl
@@ -19,6 +19,7 @@
 {{callback_invoke(
     'callback function', 'invoke',
     return_cpp_type, native_value_traits_tag, arguments,
+    is_treat_non_object_as_null,
     callback_function_name, 'invoke')}}
 }
 
@@ -27,6 +28,7 @@
 {{callback_invoke(
     'callback function', 'construct',
     return_cpp_type, native_value_traits_tag, arguments,
+    is_treat_non_object_as_null,
     callback_function_name, 'construct')}}
 }
 {% endif %}
diff --git a/third_party/blink/renderer/bindings/templates/callback_interface.cpp.tmpl b/third_party/blink/renderer/bindings/templates/callback_interface.cpp.tmpl
index 012652e7..bc03e5e 100644
--- a/third_party/blink/renderer/bindings/templates/callback_interface.cpp.tmpl
+++ b/third_party/blink/renderer/bindings/templates/callback_interface.cpp.tmpl
@@ -74,6 +74,7 @@
 {{callback_invoke(
     'callback interface', None,
     method.cpp_type, method.native_value_traits_tag, method.arguments,
+    False,
     interface_name, method.name)}}
 }
 
diff --git a/third_party/blink/renderer/bindings/templates/callback_invoke.cc.tmpl b/third_party/blink/renderer/bindings/templates/callback_invoke.cc.tmpl
index 6127fe0..25f514b 100644
--- a/third_party/blink/renderer/bindings/templates/callback_invoke.cc.tmpl
+++ b/third_party/blink/renderer/bindings/templates/callback_invoke.cc.tmpl
@@ -11,12 +11,14 @@
       return_cpp_type = Blink (C++) return type
       return_native_value_traits_tag = tag of NativeValueTraits for return type
       arguments = dict of arguments\' info
+      is_treat_non_object_as_null = True if [TreatNonObjectAsNull]
       interface_name = interface name used for exception
       operation_name = interface name used for exception and property lookup
 #}
 {% macro callback_invoke(
     interface_or_function, invoke_or_construct,
     return_cpp_type, return_native_value_traits_tag, arguments,
+    is_treat_non_object_as_null,
     interface_name, operation_name) %}
   if (!IsCallbackFunctionRunnable(CallbackRelevantScriptState(),
                                   IncumbentScriptState())) {
@@ -53,7 +55,7 @@
   // Note that step 7. and 8. are side effect free (except for a very rare
   // exception due to no incumbent realm), so it's okay to put step 3. after
   // step 7. and 8.
-  if (!CallbackFunction()->IsConstructor()) {
+  if (!IsConstructor()) {
     V8ThrowException::ThrowTypeError(
         GetIsolate(),
         ExceptionMessages::FailedToExecute(
@@ -67,12 +69,36 @@
   v8::Local<v8::Function> function;
   {# Fill |function|. #}
   {% if interface_or_function == 'callback function' %}
-  // callback function\'s invoke:
+  // callback function's invoke:
   // step 4. If ! IsCallable(F) is false:
+  {% if is_treat_non_object_as_null %}
+  if (!CallbackObject()->IsFunction()) {
+    // Handle the special case of [TreatNonObjectAsNull].
+    //
+    {% if return_cpp_type == 'void' %}
+    // step 4.1. If the callback function's return type is void, return.
+    return v8::JustVoid();
+    {% else %}
+    // step 4.2. Return the result of converting undefined to the callback
+    //   function's return type.
+    ExceptionState exception_state(GetIsolate(),
+                                   ExceptionState::kExecutionContext,
+                                   "{{interface_name}}",
+                                   "{{operation_name}}");
+    auto native_result =
+        NativeValueTraits<{{return_native_value_traits_tag}}>::NativeValue(
+            GetIsolate(), v8::Undefined(GetIsolate()), exception_state);
+    if (exception_state.HadException())
+      return v8::Nothing<{{return_cpp_type}}>();
+    else
+      return v8::Just<{{return_cpp_type}}>(native_result);
+    {% endif %}{# if return_cpp_type == 'void' #}
+  }
+  {% else %}
   //
-  // As Blink no longer supports [TreatNonObjectAsNull], there must be no such a
-  // case.
-  DCHECK(CallbackFunction()->IsFunction());
+  // No [TreatNonObjectAsNull] presents.  Must be always callable.
+  DCHECK(CallbackObject()->IsFunction());
+  {% endif %}
   function = CallbackFunction();
   {% else %}
   if (IsCallbackObjectCallable()) {
diff --git a/third_party/blink/renderer/bindings/templates/methods.cpp.tmpl b/third_party/blink/renderer/bindings/templates/methods.cpp.tmpl
index 5ab0d15..b005f2f 100644
--- a/third_party/blink/renderer/bindings/templates/methods.cpp.tmpl
+++ b/third_party/blink/renderer/bindings/templates/methods.cpp.tmpl
@@ -648,7 +648,7 @@
   {{method_configuration(method) | trim | indent(2)}}
 };
 for (const auto& methodConfig : {{method.name}}MethodConfiguration)
-  V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+  V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
 {% endfilter %}{# runtime_enabled() #}
 {% endfilter %}{# exposed() #}
 {% endfilter %}{# secure_context() #}
diff --git a/third_party/blink/renderer/bindings/tests/idls/core/test_callback_functions.idl b/third_party/blink/renderer/bindings/tests/idls/core/test_callback_functions.idl
index f7ca558..6058ac8f 100644
--- a/third_party/blink/renderer/bindings/tests/idls/core/test_callback_functions.idl
+++ b/third_party/blink/renderer/bindings/tests/idls/core/test_callback_functions.idl
@@ -16,6 +16,10 @@
 callback StringSequenceCallbackFunctionLongSequenceArg = sequence<DOMString> (sequence<long> arg);
 callback VoidCallbackFunctionEnumArg = void (TestEnum arg);
 callback VoidCallbackFunctionTypedef = void (String arg);
+[TreatNonObjectAsNull]
+callback TreatNonObjectAsNullVoidFunction = void ();
+[TreatNonObjectAsNull]
+callback TreatNonObjectAsNullBooleanFunction = boolean ();
 
 interface TestCallbackFunctions {
     // Extended attributes
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_optional_any_arg.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_optional_any_arg.cc
index ae589a2..9c94e586 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_optional_any_arg.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_optional_any_arg.cc
@@ -54,12 +54,11 @@
       IncumbentScriptState()->GetContext());
 
   v8::Local<v8::Function> function;
-  // callback function\'s invoke:
+  // callback function's invoke:
   // step 4. If ! IsCallable(F) is false:
   //
-  // As Blink no longer supports [TreatNonObjectAsNull], there must be no such a
-  // case.
-  DCHECK(CallbackFunction()->IsFunction());
+  // No [TreatNonObjectAsNull] presents.  Must be always callable.
+  DCHECK(CallbackObject()->IsFunction());
   function = CallbackFunction();
 
   v8::Local<v8::Value> this_arg;
@@ -139,7 +138,7 @@
   // Note that step 7. and 8. are side effect free (except for a very rare
   // exception due to no incumbent realm), so it's okay to put step 3. after
   // step 7. and 8.
-  if (!CallbackFunction()->IsConstructor()) {
+  if (!IsConstructor()) {
     V8ThrowException::ThrowTypeError(
         GetIsolate(),
         ExceptionMessages::FailedToExecute(
@@ -150,12 +149,11 @@
   }
 
   v8::Local<v8::Function> function;
-  // callback function\'s invoke:
+  // callback function's invoke:
   // step 4. If ! IsCallable(F) is false:
   //
-  // As Blink no longer supports [TreatNonObjectAsNull], there must be no such a
-  // case.
-  DCHECK(CallbackFunction()->IsFunction());
+  // No [TreatNonObjectAsNull] presents.  Must be always callable.
+  DCHECK(CallbackObject()->IsFunction());
   function = CallbackFunction();
 
   // step: Let esArgs be the result of converting args to an ECMAScript
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_variadic_any_args.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_variadic_any_args.cc
index 9586117..d44c397d 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_variadic_any_args.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_any_callback_function_variadic_any_args.cc
@@ -54,12 +54,11 @@
       IncumbentScriptState()->GetContext());
 
   v8::Local<v8::Function> function;
-  // callback function\'s invoke:
+  // callback function's invoke:
   // step 4. If ! IsCallable(F) is false:
   //
-  // As Blink no longer supports [TreatNonObjectAsNull], there must be no such a
-  // case.
-  DCHECK(CallbackFunction()->IsFunction());
+  // No [TreatNonObjectAsNull] presents.  Must be always callable.
+  DCHECK(CallbackObject()->IsFunction());
   function = CallbackFunction();
 
   v8::Local<v8::Value> this_arg;
@@ -140,7 +139,7 @@
   // Note that step 7. and 8. are side effect free (except for a very rare
   // exception due to no incumbent realm), so it's okay to put step 3. after
   // step 7. and 8.
-  if (!CallbackFunction()->IsConstructor()) {
+  if (!IsConstructor()) {
     V8ThrowException::ThrowTypeError(
         GetIsolate(),
         ExceptionMessages::FailedToExecute(
@@ -151,12 +150,11 @@
   }
 
   v8::Local<v8::Function> function;
-  // callback function\'s invoke:
+  // callback function's invoke:
   // step 4. If ! IsCallable(F) is false:
   //
-  // As Blink no longer supports [TreatNonObjectAsNull], there must be no such a
-  // case.
-  DCHECK(CallbackFunction()->IsFunction());
+  // No [TreatNonObjectAsNull] presents.  Must be always callable.
+  DCHECK(CallbackObject()->IsFunction());
   function = CallbackFunction();
 
   // step: Let esArgs be the result of converting args to an ECMAScript
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_long_callback_function.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_long_callback_function.cc
index 7a6e2e1..194975f 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_long_callback_function.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_long_callback_function.cc
@@ -54,12 +54,11 @@
       IncumbentScriptState()->GetContext());
 
   v8::Local<v8::Function> function;
-  // callback function\'s invoke:
+  // callback function's invoke:
   // step 4. If ! IsCallable(F) is false:
   //
-  // As Blink no longer supports [TreatNonObjectAsNull], there must be no such a
-  // case.
-  DCHECK(CallbackFunction()->IsFunction());
+  // No [TreatNonObjectAsNull] presents.  Must be always callable.
+  DCHECK(CallbackObject()->IsFunction());
   function = CallbackFunction();
 
   v8::Local<v8::Value> this_arg;
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_string_sequence_callback_function_long_sequence_arg.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_string_sequence_callback_function_long_sequence_arg.cc
index ca17584..02fabbb 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_string_sequence_callback_function_long_sequence_arg.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_string_sequence_callback_function_long_sequence_arg.cc
@@ -54,12 +54,11 @@
       IncumbentScriptState()->GetContext());
 
   v8::Local<v8::Function> function;
-  // callback function\'s invoke:
+  // callback function's invoke:
   // step 4. If ! IsCallable(F) is false:
   //
-  // As Blink no longer supports [TreatNonObjectAsNull], there must be no such a
-  // case.
-  DCHECK(CallbackFunction()->IsFunction());
+  // No [TreatNonObjectAsNull] presents.  Must be always callable.
+  DCHECK(CallbackObject()->IsFunction());
   function = CallbackFunction();
 
   v8::Local<v8::Value> this_arg;
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface.cc
index e4ffca3..41f24183 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface.cc
@@ -4089,14 +4089,14 @@
         {"workerExposedMethod", V8TestInterface::workerExposedMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
       };
       for (const auto& methodConfig : workerExposedMethodMethodConfiguration)
-        V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+        V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
     }
     if (executionContext && (executionContext->IsDocument())) {
       const V8DOMConfiguration::MethodConfiguration windowExposedMethodMethodConfiguration[] = {
         {"windowExposedMethod", V8TestInterface::windowExposedMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
       };
       for (const auto& methodConfig : windowExposedMethodMethodConfiguration)
-        V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+        V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
     }
     if (executionContext && (executionContext->IsDocument())) {
       if (RuntimeEnabledFeatures::FeatureNameEnabled()) {
@@ -4104,7 +4104,7 @@
           {"methodWithExposedAndRuntimeEnabledFlag", V8TestInterface::methodWithExposedAndRuntimeEnabledFlagMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
         };
         for (const auto& methodConfig : methodWithExposedAndRuntimeEnabledFlagMethodConfiguration)
-          V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+          V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
       }
     }
     if (executionContext && (executionContext->IsDocument())) {
@@ -4112,28 +4112,28 @@
         {"overloadMethodWithExposedAndRuntimeEnabledFlag", V8TestInterface::overloadMethodWithExposedAndRuntimeEnabledFlagMethodCallback, 1, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
       };
       for (const auto& methodConfig : overloadMethodWithExposedAndRuntimeEnabledFlagMethodConfiguration)
-        V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+        V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
     }
     if (executionContext && ((executionContext->IsDocument() && RuntimeEnabledFeatures::FeatureNameEnabled()) || (executionContext->IsWorkerGlobalScope() && RuntimeEnabledFeatures::FeatureName2Enabled()))) {
       const V8DOMConfiguration::MethodConfiguration methodWithExposedHavingRuntimeEnabldFlagMethodConfiguration[] = {
         {"methodWithExposedHavingRuntimeEnabldFlag", V8TestInterface::methodWithExposedHavingRuntimeEnabldFlagMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
       };
       for (const auto& methodConfig : methodWithExposedHavingRuntimeEnabldFlagMethodConfiguration)
-        V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+        V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
     }
     if (executionContext && (executionContext->IsDocument() || executionContext->IsServiceWorkerGlobalScope())) {
       const V8DOMConfiguration::MethodConfiguration windowAndServiceWorkerExposedMethodMethodConfiguration[] = {
         {"windowAndServiceWorkerExposedMethod", V8TestInterface::windowAndServiceWorkerExposedMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
       };
       for (const auto& methodConfig : windowAndServiceWorkerExposedMethodMethodConfiguration)
-        V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+        V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
     }
     if (isSecureContext) {
       const V8DOMConfiguration::MethodConfiguration secureContextMethodMethodConfiguration[] = {
         {"secureContextMethod", V8TestInterface::secureContextMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
       };
       for (const auto& methodConfig : secureContextMethodMethodConfiguration)
-        V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+        V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
     }
     if (isSecureContext) {
       if (RuntimeEnabledFeatures::SecureFeatureEnabled()) {
@@ -4141,7 +4141,7 @@
           {"secureContextRuntimeEnabledMethod", V8TestInterface::secureContextRuntimeEnabledMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
         };
         for (const auto& methodConfig : secureContextRuntimeEnabledMethodMethodConfiguration)
-          V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+          V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
       }
     }
     if (isSecureContext || !RuntimeEnabledFeatures::SecureContextnessFeatureEnabled()) {
@@ -4149,7 +4149,7 @@
         {"secureContextnessRuntimeEnabledMethod", V8TestInterface::secureContextnessRuntimeEnabledMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
       };
       for (const auto& methodConfig : secureContextnessRuntimeEnabledMethodMethodConfiguration)
-        V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+        V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
     }
     if (isSecureContext) {
       if (executionContext && (executionContext->IsDocument())) {
@@ -4157,7 +4157,7 @@
           {"secureContextWindowExposedMethod", V8TestInterface::secureContextWindowExposedMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
         };
         for (const auto& methodConfig : secureContextWindowExposedMethodMethodConfiguration)
-          V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+          V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
       }
     }
     if (isSecureContext) {
@@ -4166,7 +4166,7 @@
           {"secureContextWorkerExposedMethod", V8TestInterface::secureContextWorkerExposedMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
         };
         for (const auto& methodConfig : secureContextWorkerExposedMethodMethodConfiguration)
-          V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+          V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
       }
     }
     if (isSecureContext) {
@@ -4176,7 +4176,7 @@
             {"secureContextWindowExposedRuntimeEnabledMethod", V8TestInterface::secureContextWindowExposedRuntimeEnabledMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
           };
           for (const auto& methodConfig : secureContextWindowExposedRuntimeEnabledMethodMethodConfiguration)
-            V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+            V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
         }
       }
     }
@@ -4187,7 +4187,7 @@
             {"secureContextWorkerExposedRuntimeEnabledMethod", V8TestInterface::secureContextWorkerExposedRuntimeEnabledMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
           };
           for (const auto& methodConfig : secureContextWorkerExposedRuntimeEnabledMethodMethodConfiguration)
-            V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+            V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
         }
       }
     }
@@ -4196,14 +4196,14 @@
         {"partial2SecureContextMethod", V8TestInterface::partial2SecureContextMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
       };
       for (const auto& methodConfig : partial2SecureContextMethodMethodConfiguration)
-        V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+        V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
     }
     if (isSecureContext) {
       const V8DOMConfiguration::MethodConfiguration partialSecureContextMethodMethodConfiguration[] = {
         {"partialSecureContextMethod", V8TestInterface::partialSecureContextMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
       };
       for (const auto& methodConfig : partialSecureContextMethodMethodConfiguration)
-        V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+        V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
     }
     if (isSecureContext) {
       if (RuntimeEnabledFeatures::SecureFeatureEnabled()) {
@@ -4211,7 +4211,7 @@
           {"partialSecureContextRuntimeEnabledMethod", V8TestInterface::partialSecureContextRuntimeEnabledMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
         };
         for (const auto& methodConfig : partialSecureContextRuntimeEnabledMethodMethodConfiguration)
-          V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+          V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
       }
     }
     if (isSecureContext) {
@@ -4220,7 +4220,7 @@
           {"partialSecureContextWindowExposedMethod", V8TestInterface::partialSecureContextWindowExposedMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
         };
         for (const auto& methodConfig : partialSecureContextWindowExposedMethodMethodConfiguration)
-          V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+          V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
       }
     }
     if (isSecureContext) {
@@ -4229,7 +4229,7 @@
           {"partialSecureContextWorkerExposedMethod", V8TestInterface::partialSecureContextWorkerExposedMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
         };
         for (const auto& methodConfig : partialSecureContextWorkerExposedMethodMethodConfiguration)
-          V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+          V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
       }
     }
     if (isSecureContext) {
@@ -4239,7 +4239,7 @@
             {"partialSecureContextWindowExposedRuntimeEnabledMethod", V8TestInterface::partialSecureContextWindowExposedRuntimeEnabledMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
           };
           for (const auto& methodConfig : partialSecureContextWindowExposedRuntimeEnabledMethodMethodConfiguration)
-            V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+            V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
         }
       }
     }
@@ -4250,7 +4250,7 @@
             {"partialSecureContextWorkerExposedRuntimeEnabledMethod", V8TestInterface::partialSecureContextWorkerExposedRuntimeEnabledMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
           };
           for (const auto& methodConfig : partialSecureContextWorkerExposedRuntimeEnabledMethodMethodConfiguration)
-            V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+            V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
         }
       }
     }
@@ -4259,14 +4259,14 @@
         {"workerExposedStaticMethod", V8TestInterface::workerExposedStaticMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnInterface, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
       };
       for (const auto& methodConfig : workerExposedStaticMethodMethodConfiguration)
-        V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+        V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
     }
     if (executionContext && (executionContext->IsDocument())) {
       const V8DOMConfiguration::MethodConfiguration windowExposedStaticMethodMethodConfiguration[] = {
         {"windowExposedStaticMethod", V8TestInterface::windowExposedStaticMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnInterface, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
       };
       for (const auto& methodConfig : windowExposedStaticMethodMethodConfiguration)
-        V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+        V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
     }
   }
 }
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_check_security.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_check_security.cc
index 2f9491a..0bf270e 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_check_security.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_check_security.cc
@@ -865,7 +865,7 @@
           {"secureContextRuntimeEnabledMethod", V8TestInterfaceCheckSecurity::secureContextRuntimeEnabledMethodMethodCallback, 1, v8::None, V8DOMConfiguration::kOnInstance, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
         };
         for (const auto& methodConfig : secureContextRuntimeEnabledMethodMethodConfiguration)
-          V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+          V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
       }
     }
   }
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_conditional_secure_context.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_conditional_secure_context.cc
index 0636e2b..dfe293a 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_conditional_secure_context.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_conditional_secure_context.cc
@@ -529,7 +529,7 @@
         {"secureContextMethod", V8TestInterfaceConditionalSecureContext::secureContextMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
       };
       for (const auto& methodConfig : secureContextMethodMethodConfiguration)
-        V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+        V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
     }
     if (isSecureContext || !RuntimeEnabledFeatures::SecureContextnessFeatureEnabled()) {
       if (RuntimeEnabledFeatures::SecureFeatureEnabled()) {
@@ -537,7 +537,7 @@
           {"secureContextRuntimeEnabledMethod", V8TestInterfaceConditionalSecureContext::secureContextRuntimeEnabledMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
         };
         for (const auto& methodConfig : secureContextRuntimeEnabledMethodMethodConfiguration)
-          V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+          V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
       }
     }
     if (isSecureContext || !RuntimeEnabledFeatures::SecureContextnessFeatureEnabled()) {
@@ -546,7 +546,7 @@
           {"secureContextWindowExposedMethod", V8TestInterfaceConditionalSecureContext::secureContextWindowExposedMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
         };
         for (const auto& methodConfig : secureContextWindowExposedMethodMethodConfiguration)
-          V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+          V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
       }
     }
     if (isSecureContext || !RuntimeEnabledFeatures::SecureContextnessFeatureEnabled()) {
@@ -555,7 +555,7 @@
           {"secureContextWorkerExposedMethod", V8TestInterfaceConditionalSecureContext::secureContextWorkerExposedMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
         };
         for (const auto& methodConfig : secureContextWorkerExposedMethodMethodConfiguration)
-          V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+          V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
       }
     }
     if (isSecureContext || !RuntimeEnabledFeatures::SecureContextnessFeatureEnabled()) {
@@ -565,7 +565,7 @@
             {"secureContextWindowExposedRuntimeEnabledMethod", V8TestInterfaceConditionalSecureContext::secureContextWindowExposedRuntimeEnabledMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
           };
           for (const auto& methodConfig : secureContextWindowExposedRuntimeEnabledMethodMethodConfiguration)
-            V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+            V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
         }
       }
     }
@@ -576,7 +576,7 @@
             {"secureContextWorkerExposedRuntimeEnabledMethod", V8TestInterfaceConditionalSecureContext::secureContextWorkerExposedRuntimeEnabledMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
           };
           for (const auto& methodConfig : secureContextWorkerExposedRuntimeEnabledMethodMethodConfiguration)
-            V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+            V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
         }
       }
     }
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_secure_context.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_secure_context.cc
index fe616b64..0f9910b 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_secure_context.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_test_interface_secure_context.cc
@@ -529,7 +529,7 @@
         {"secureContextMethod", V8TestInterfaceSecureContext::secureContextMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
       };
       for (const auto& methodConfig : secureContextMethodMethodConfiguration)
-        V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+        V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
     }
     if (isSecureContext) {
       if (RuntimeEnabledFeatures::SecureFeatureEnabled()) {
@@ -537,7 +537,7 @@
           {"secureContextRuntimeEnabledMethod", V8TestInterfaceSecureContext::secureContextRuntimeEnabledMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
         };
         for (const auto& methodConfig : secureContextRuntimeEnabledMethodMethodConfiguration)
-          V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+          V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
       }
     }
     if (isSecureContext) {
@@ -546,7 +546,7 @@
           {"secureContextWindowExposedMethod", V8TestInterfaceSecureContext::secureContextWindowExposedMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
         };
         for (const auto& methodConfig : secureContextWindowExposedMethodMethodConfiguration)
-          V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+          V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
       }
     }
     if (isSecureContext) {
@@ -555,7 +555,7 @@
           {"secureContextWorkerExposedMethod", V8TestInterfaceSecureContext::secureContextWorkerExposedMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
         };
         for (const auto& methodConfig : secureContextWorkerExposedMethodMethodConfiguration)
-          V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+          V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
       }
     }
     if (isSecureContext) {
@@ -565,7 +565,7 @@
             {"secureContextWindowExposedRuntimeEnabledMethod", V8TestInterfaceSecureContext::secureContextWindowExposedRuntimeEnabledMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
           };
           for (const auto& methodConfig : secureContextWindowExposedRuntimeEnabledMethodMethodConfiguration)
-            V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+            V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
         }
       }
     }
@@ -576,7 +576,7 @@
             {"secureContextWorkerExposedRuntimeEnabledMethod", V8TestInterfaceSecureContext::secureContextWorkerExposedRuntimeEnabledMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
           };
           for (const auto& methodConfig : secureContextWorkerExposedRuntimeEnabledMethodMethodConfiguration)
-            V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+            V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
         }
       }
     }
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_boolean_function.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_boolean_function.cc
new file mode 100644
index 0000000..7868a24
--- /dev/null
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_boolean_function.cc
@@ -0,0 +1,123 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file has been auto-generated from the Jinja2 template
+// third_party/blink/renderer/bindings/templates/callback_function.cpp.tmpl
+// by the script code_generator_v8.py.
+// DO NOT MODIFY!
+
+// clang-format off
+
+#include "third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_boolean_function.h"
+
+#include "base/stl_util.h"
+#include "third_party/blink/renderer/bindings/core/v8/generated_code_helper.h"
+#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
+#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/platform/bindings/exception_messages.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+
+namespace blink {
+
+const char* V8TreatNonObjectAsNullBooleanFunction::NameInHeapSnapshot() const {
+  return "V8TreatNonObjectAsNullBooleanFunction";
+}
+
+v8::Maybe<bool> V8TreatNonObjectAsNullBooleanFunction::Invoke(ScriptWrappable* callback_this_value) {
+  if (!IsCallbackFunctionRunnable(CallbackRelevantScriptState(),
+                                  IncumbentScriptState())) {
+    // Wrapper-tracing for the callback function makes the function object and
+    // its creation context alive. Thus it's safe to use the creation context
+    // of the callback function here.
+    v8::HandleScope handle_scope(GetIsolate());
+    v8::Local<v8::Object> callback_object = CallbackFunction();
+    CHECK(!callback_object.IsEmpty());
+    v8::Context::Scope context_scope(callback_object->CreationContext());
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "TreatNonObjectAsNullBooleanFunction",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<bool>();
+  }
+
+  // step: Prepare to run script with relevant settings.
+  ScriptState::Scope callback_relevant_context_scope(
+      CallbackRelevantScriptState());
+  // step: Prepare to run a callback with stored settings.
+  v8::Context::BackupIncumbentScope backup_incumbent_scope(
+      IncumbentScriptState()->GetContext());
+
+  v8::Local<v8::Function> function;
+  // callback function's invoke:
+  // step 4. If ! IsCallable(F) is false:
+  if (!CallbackObject()->IsFunction()) {
+    // Handle the special case of [TreatNonObjectAsNull].
+    //
+    // step 4.2. Return the result of converting undefined to the callback
+    //   function's return type.
+    ExceptionState exception_state(GetIsolate(),
+                                   ExceptionState::kExecutionContext,
+                                   "TreatNonObjectAsNullBooleanFunction",
+                                   "invoke");
+    auto native_result =
+        NativeValueTraits<IDLBoolean>::NativeValue(
+            GetIsolate(), v8::Undefined(GetIsolate()), exception_state);
+    if (exception_state.HadException())
+      return v8::Nothing<bool>();
+    else
+      return v8::Just<bool>(native_result);
+  }
+  function = CallbackFunction();
+
+  v8::Local<v8::Value> this_arg;
+  this_arg = ToV8(callback_this_value, CallbackRelevantScriptState());
+
+  // step: Let esArgs be the result of converting args to an ECMAScript
+  //   arguments list. If this throws an exception, set completion to the
+  //   completion value representing the thrown exception and jump to the step
+  //   labeled return.
+  const int argc = 0;
+  v8::Local<v8::Value> *argv = nullptr;
+
+  v8::Local<v8::Value> call_result;
+  // step: Let callResult be Call(X, thisArg, esArgs).
+  if (!V8ScriptRunner::CallFunction(
+          function,
+          ExecutionContext::From(CallbackRelevantScriptState()),
+          this_arg,
+          argc,
+          argv,
+          GetIsolate()).ToLocal(&call_result)) {
+    // step: If callResult is an abrupt completion, set completion to callResult
+    //   and jump to the step labeled return.
+    return v8::Nothing<bool>();
+  }
+
+  // step: Set completion to the result of converting callResult.[[Value]] to
+  //   an IDL value of the same type as the operation's return type.
+  {
+    ExceptionState exception_state(GetIsolate(),
+                                   ExceptionState::kExecutionContext,
+                                   "TreatNonObjectAsNullBooleanFunction",
+                                   "invoke");
+    auto native_result =
+        NativeValueTraits<IDLBoolean>::NativeValue(
+            GetIsolate(), call_result, exception_state);
+    if (exception_state.HadException())
+      return v8::Nothing<bool>();
+    else
+      return v8::Just<bool>(native_result);
+  }
+}
+
+v8::Maybe<bool> V8PersistentCallbackFunction<V8TreatNonObjectAsNullBooleanFunction>::Invoke(ScriptWrappable* callback_this_value) {
+  return Proxy()->Invoke(
+      callback_this_value);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_boolean_function.h b/third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_boolean_function.h
new file mode 100644
index 0000000..78b6e4f
--- /dev/null
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_boolean_function.h
@@ -0,0 +1,76 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file has been auto-generated from the Jinja2 template
+// third_party/blink/renderer/bindings/templates/callback_function.h.tmpl
+// by the script code_generator_v8.py.
+// DO NOT MODIFY!
+
+// clang-format off
+
+#ifndef V8TreatNonObjectAsNullBooleanFunction_h
+#define V8TreatNonObjectAsNullBooleanFunction_h
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/bindings/callback_function_base.h"
+
+namespace blink {
+
+class ScriptWrappable;
+
+class CORE_EXPORT V8TreatNonObjectAsNullBooleanFunction final : public CallbackFunctionBase {
+ public:
+  static V8TreatNonObjectAsNullBooleanFunction* Create(v8::Local<v8::Function> callback_function) {
+    return new V8TreatNonObjectAsNullBooleanFunction(callback_function);
+  }
+
+  ~V8TreatNonObjectAsNullBooleanFunction() override = default;
+
+  // NameClient overrides:
+  const char* NameInHeapSnapshot() const override;
+
+  // Performs "invoke".
+  // https://heycam.github.io/webidl/#es-invoking-callback-functions
+  v8::Maybe<bool> Invoke(ScriptWrappable* callback_this_value) WARN_UNUSED_RESULT;
+
+ private:
+  explicit V8TreatNonObjectAsNullBooleanFunction(v8::Local<v8::Function> callback_function)
+      : CallbackFunctionBase(callback_function) {}
+};
+
+template <>
+class V8PersistentCallbackFunction<V8TreatNonObjectAsNullBooleanFunction> final : public V8PersistentCallbackFunctionBase {
+  using V8CallbackFunction = V8TreatNonObjectAsNullBooleanFunction;
+
+ public:
+  ~V8PersistentCallbackFunction() override = default;
+
+  // Returns a wrapper-tracing version of this callback function.
+  V8CallbackFunction* ToNonV8Persistent() { return Proxy(); }
+
+  v8::Maybe<bool> Invoke(ScriptWrappable* callback_this_value) WARN_UNUSED_RESULT;
+
+ private:
+  explicit V8PersistentCallbackFunction(V8CallbackFunction* callback_function)
+      : V8PersistentCallbackFunctionBase(callback_function) {}
+
+  V8CallbackFunction* Proxy() {
+    return As<V8CallbackFunction>();
+  }
+
+  template <typename V8CallbackFunction>
+  friend V8PersistentCallbackFunction<V8CallbackFunction>*
+  ToV8PersistentCallbackFunction(V8CallbackFunction*);
+};
+
+// V8TreatNonObjectAsNullBooleanFunction is designed to be used with wrapper-tracing.
+// As blink::Persistent does not perform wrapper-tracing, use of
+// |WrapPersistent| for callback functions is likely (if not always) misuse.
+// Thus, this code prohibits such a use case. The call sites should explicitly
+// use WrapPersistent(V8PersistentCallbackFunction<T>*).
+Persistent<V8TreatNonObjectAsNullBooleanFunction> WrapPersistent(V8TreatNonObjectAsNullBooleanFunction*) = delete;
+
+}  // namespace blink
+
+#endif  // V8TreatNonObjectAsNullBooleanFunction_h
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_void_function.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_void_function.cc
new file mode 100644
index 0000000..b6d59ba
--- /dev/null
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_void_function.cc
@@ -0,0 +1,115 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file has been auto-generated from the Jinja2 template
+// third_party/blink/renderer/bindings/templates/callback_function.cpp.tmpl
+// by the script code_generator_v8.py.
+// DO NOT MODIFY!
+
+// clang-format off
+
+#include "third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_void_function.h"
+
+#include "base/stl_util.h"
+#include "third_party/blink/renderer/bindings/core/v8/generated_code_helper.h"
+#include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
+#include "third_party/blink/renderer/bindings/core/v8/to_v8_for_core.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_core.h"
+#include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/platform/bindings/exception_messages.h"
+#include "third_party/blink/renderer/platform/bindings/exception_state.h"
+
+namespace blink {
+
+const char* V8TreatNonObjectAsNullVoidFunction::NameInHeapSnapshot() const {
+  return "V8TreatNonObjectAsNullVoidFunction";
+}
+
+v8::Maybe<void> V8TreatNonObjectAsNullVoidFunction::Invoke(ScriptWrappable* callback_this_value) {
+  if (!IsCallbackFunctionRunnable(CallbackRelevantScriptState(),
+                                  IncumbentScriptState())) {
+    // Wrapper-tracing for the callback function makes the function object and
+    // its creation context alive. Thus it's safe to use the creation context
+    // of the callback function here.
+    v8::HandleScope handle_scope(GetIsolate());
+    v8::Local<v8::Object> callback_object = CallbackFunction();
+    CHECK(!callback_object.IsEmpty());
+    v8::Context::Scope context_scope(callback_object->CreationContext());
+    V8ThrowException::ThrowError(
+        GetIsolate(),
+        ExceptionMessages::FailedToExecute(
+            "invoke",
+            "TreatNonObjectAsNullVoidFunction",
+            "The provided callback is no longer runnable."));
+    return v8::Nothing<void>();
+  }
+
+  // step: Prepare to run script with relevant settings.
+  ScriptState::Scope callback_relevant_context_scope(
+      CallbackRelevantScriptState());
+  // step: Prepare to run a callback with stored settings.
+  v8::Context::BackupIncumbentScope backup_incumbent_scope(
+      IncumbentScriptState()->GetContext());
+
+  v8::Local<v8::Function> function;
+  // callback function's invoke:
+  // step 4. If ! IsCallable(F) is false:
+  if (!CallbackObject()->IsFunction()) {
+    // Handle the special case of [TreatNonObjectAsNull].
+    //
+    // step 4.1. If the callback function's return type is void, return.
+    return v8::JustVoid();
+  }
+  function = CallbackFunction();
+
+  v8::Local<v8::Value> this_arg;
+  this_arg = ToV8(callback_this_value, CallbackRelevantScriptState());
+
+  // step: Let esArgs be the result of converting args to an ECMAScript
+  //   arguments list. If this throws an exception, set completion to the
+  //   completion value representing the thrown exception and jump to the step
+  //   labeled return.
+  const int argc = 0;
+  v8::Local<v8::Value> *argv = nullptr;
+
+  v8::Local<v8::Value> call_result;
+  // step: Let callResult be Call(X, thisArg, esArgs).
+  if (!V8ScriptRunner::CallFunction(
+          function,
+          ExecutionContext::From(CallbackRelevantScriptState()),
+          this_arg,
+          argc,
+          argv,
+          GetIsolate()).ToLocal(&call_result)) {
+    // step: If callResult is an abrupt completion, set completion to callResult
+    //   and jump to the step labeled return.
+    return v8::Nothing<void>();
+  }
+
+  // step: Set completion to the result of converting callResult.[[Value]] to
+  //   an IDL value of the same type as the operation's return type.
+  return v8::JustVoid();
+}
+
+void V8TreatNonObjectAsNullVoidFunction::InvokeAndReportException(ScriptWrappable* callback_this_value) {
+  v8::TryCatch try_catch(GetIsolate());
+  try_catch.SetVerbose(true);
+
+  v8::Maybe<void> maybe_result =
+      Invoke(callback_this_value);
+  // An exception if any is killed with the v8::TryCatch above.
+  ALLOW_UNUSED_LOCAL(maybe_result);
+}
+
+v8::Maybe<void> V8PersistentCallbackFunction<V8TreatNonObjectAsNullVoidFunction>::Invoke(ScriptWrappable* callback_this_value) {
+  return Proxy()->Invoke(
+      callback_this_value);
+}
+
+void V8PersistentCallbackFunction<V8TreatNonObjectAsNullVoidFunction>::InvokeAndReportException(ScriptWrappable* callback_this_value) {
+  Proxy()->InvokeAndReportException(
+      callback_this_value);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_void_function.h b/third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_void_function.h
new file mode 100644
index 0000000..a77b3f6
--- /dev/null
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_treat_non_object_as_null_void_function.h
@@ -0,0 +1,81 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// This file has been auto-generated from the Jinja2 template
+// third_party/blink/renderer/bindings/templates/callback_function.h.tmpl
+// by the script code_generator_v8.py.
+// DO NOT MODIFY!
+
+// clang-format off
+
+#ifndef V8TreatNonObjectAsNullVoidFunction_h
+#define V8TreatNonObjectAsNullVoidFunction_h
+
+#include "third_party/blink/renderer/core/core_export.h"
+#include "third_party/blink/renderer/platform/bindings/callback_function_base.h"
+
+namespace blink {
+
+class ScriptWrappable;
+
+class CORE_EXPORT V8TreatNonObjectAsNullVoidFunction final : public CallbackFunctionBase {
+ public:
+  static V8TreatNonObjectAsNullVoidFunction* Create(v8::Local<v8::Function> callback_function) {
+    return new V8TreatNonObjectAsNullVoidFunction(callback_function);
+  }
+
+  ~V8TreatNonObjectAsNullVoidFunction() override = default;
+
+  // NameClient overrides:
+  const char* NameInHeapSnapshot() const override;
+
+  // Performs "invoke".
+  // https://heycam.github.io/webidl/#es-invoking-callback-functions
+  v8::Maybe<void> Invoke(ScriptWrappable* callback_this_value) WARN_UNUSED_RESULT;
+
+  // Performs "invoke", and then reports an exception, if any, to the global
+  // error handler such as DevTools' console.
+  void InvokeAndReportException(ScriptWrappable* callback_this_value);
+
+ private:
+  explicit V8TreatNonObjectAsNullVoidFunction(v8::Local<v8::Function> callback_function)
+      : CallbackFunctionBase(callback_function) {}
+};
+
+template <>
+class V8PersistentCallbackFunction<V8TreatNonObjectAsNullVoidFunction> final : public V8PersistentCallbackFunctionBase {
+  using V8CallbackFunction = V8TreatNonObjectAsNullVoidFunction;
+
+ public:
+  ~V8PersistentCallbackFunction() override = default;
+
+  // Returns a wrapper-tracing version of this callback function.
+  V8CallbackFunction* ToNonV8Persistent() { return Proxy(); }
+
+  v8::Maybe<void> Invoke(ScriptWrappable* callback_this_value) WARN_UNUSED_RESULT;
+  CORE_EXPORT void InvokeAndReportException(ScriptWrappable* callback_this_value);
+
+ private:
+  explicit V8PersistentCallbackFunction(V8CallbackFunction* callback_function)
+      : V8PersistentCallbackFunctionBase(callback_function) {}
+
+  V8CallbackFunction* Proxy() {
+    return As<V8CallbackFunction>();
+  }
+
+  template <typename V8CallbackFunction>
+  friend V8PersistentCallbackFunction<V8CallbackFunction>*
+  ToV8PersistentCallbackFunction(V8CallbackFunction*);
+};
+
+// V8TreatNonObjectAsNullVoidFunction is designed to be used with wrapper-tracing.
+// As blink::Persistent does not perform wrapper-tracing, use of
+// |WrapPersistent| for callback functions is likely (if not always) misuse.
+// Thus, this code prohibits such a use case. The call sites should explicitly
+// use WrapPersistent(V8PersistentCallbackFunction<T>*).
+Persistent<V8TreatNonObjectAsNullVoidFunction> WrapPersistent(V8TreatNonObjectAsNullVoidFunction*) = delete;
+
+}  // namespace blink
+
+#endif  // V8TreatNonObjectAsNullVoidFunction_h
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function.cc
index f23c198d..4604b860 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function.cc
@@ -53,12 +53,11 @@
       IncumbentScriptState()->GetContext());
 
   v8::Local<v8::Function> function;
-  // callback function\'s invoke:
+  // callback function's invoke:
   // step 4. If ! IsCallable(F) is false:
   //
-  // As Blink no longer supports [TreatNonObjectAsNull], there must be no such a
-  // case.
-  DCHECK(CallbackFunction()->IsFunction());
+  // No [TreatNonObjectAsNull] presents.  Must be always callable.
+  DCHECK(CallbackObject()->IsFunction());
   function = CallbackFunction();
 
   v8::Local<v8::Value> this_arg;
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_dictionary_arg.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_dictionary_arg.cc
index f2d1457..f11cbda 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_dictionary_arg.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_dictionary_arg.cc
@@ -54,12 +54,11 @@
       IncumbentScriptState()->GetContext());
 
   v8::Local<v8::Function> function;
-  // callback function\'s invoke:
+  // callback function's invoke:
   // step 4. If ! IsCallable(F) is false:
   //
-  // As Blink no longer supports [TreatNonObjectAsNull], there must be no such a
-  // case.
-  DCHECK(CallbackFunction()->IsFunction());
+  // No [TreatNonObjectAsNull] presents.  Must be always callable.
+  DCHECK(CallbackObject()->IsFunction());
   function = CallbackFunction();
 
   v8::Local<v8::Value> this_arg;
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_enum_arg.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_enum_arg.cc
index f741b1e..42e1729 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_enum_arg.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_enum_arg.cc
@@ -54,12 +54,11 @@
       IncumbentScriptState()->GetContext());
 
   v8::Local<v8::Function> function;
-  // callback function\'s invoke:
+  // callback function's invoke:
   // step 4. If ! IsCallable(F) is false:
   //
-  // As Blink no longer supports [TreatNonObjectAsNull], there must be no such a
-  // case.
-  DCHECK(CallbackFunction()->IsFunction());
+  // No [TreatNonObjectAsNull] presents.  Must be always callable.
+  DCHECK(CallbackObject()->IsFunction());
   function = CallbackFunction();
 
   v8::Local<v8::Value> this_arg;
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_interface_arg.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_interface_arg.cc
index 071bb6f..3e66d4f 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_interface_arg.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_interface_arg.cc
@@ -54,12 +54,11 @@
       IncumbentScriptState()->GetContext());
 
   v8::Local<v8::Function> function;
-  // callback function\'s invoke:
+  // callback function's invoke:
   // step 4. If ! IsCallable(F) is false:
   //
-  // As Blink no longer supports [TreatNonObjectAsNull], there must be no such a
-  // case.
-  DCHECK(CallbackFunction()->IsFunction());
+  // No [TreatNonObjectAsNull] presents.  Must be always callable.
+  DCHECK(CallbackObject()->IsFunction());
   function = CallbackFunction();
 
   v8::Local<v8::Value> this_arg;
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_test_interface_sequence_arg.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_test_interface_sequence_arg.cc
index 4ca8e4bac..2b970bf 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_test_interface_sequence_arg.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_test_interface_sequence_arg.cc
@@ -55,12 +55,11 @@
       IncumbentScriptState()->GetContext());
 
   v8::Local<v8::Function> function;
-  // callback function\'s invoke:
+  // callback function's invoke:
   // step 4. If ! IsCallable(F) is false:
   //
-  // As Blink no longer supports [TreatNonObjectAsNull], there must be no such a
-  // case.
-  DCHECK(CallbackFunction()->IsFunction());
+  // No [TreatNonObjectAsNull] presents.  Must be always callable.
+  DCHECK(CallbackObject()->IsFunction());
   function = CallbackFunction();
 
   v8::Local<v8::Value> this_arg;
diff --git a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_typedef.cc b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_typedef.cc
index 78893d0..9952e59 100644
--- a/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_typedef.cc
+++ b/third_party/blink/renderer/bindings/tests/results/core/v8_void_callback_function_typedef.cc
@@ -54,12 +54,11 @@
       IncumbentScriptState()->GetContext());
 
   v8::Local<v8::Function> function;
-  // callback function\'s invoke:
+  // callback function's invoke:
   // step 4. If ! IsCallable(F) is false:
   //
-  // As Blink no longer supports [TreatNonObjectAsNull], there must be no such a
-  // case.
-  DCHECK(CallbackFunction()->IsFunction());
+  // No [TreatNonObjectAsNull] presents.  Must be always callable.
+  DCHECK(CallbackObject()->IsFunction());
   function = CallbackFunction();
 
   v8::Local<v8::Value> this_arg;
diff --git a/third_party/blink/renderer/bindings/tests/results/modules/v8_test_interface_5.cc b/third_party/blink/renderer/bindings/tests/results/modules/v8_test_interface_5.cc
index 422d7ede..4c80b44 100644
--- a/third_party/blink/renderer/bindings/tests/results/modules/v8_test_interface_5.cc
+++ b/third_party/blink/renderer/bindings/tests/results/modules/v8_test_interface_5.cc
@@ -1100,35 +1100,35 @@
         {"workerExposedMethod", V8TestInterface5::workerExposedMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
       };
       for (const auto& methodConfig : workerExposedMethodMethodConfiguration)
-        V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+        V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
     }
     if (executionContext && (executionContext->IsDocument())) {
       const V8DOMConfiguration::MethodConfiguration windowExposedMethodMethodConfiguration[] = {
         {"windowExposedMethod", V8TestInterface5::windowExposedMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
       };
       for (const auto& methodConfig : windowExposedMethodMethodConfiguration)
-        V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+        V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
     }
     if (executionContext && (executionContext->IsDocument() || executionContext->IsServiceWorkerGlobalScope())) {
       const V8DOMConfiguration::MethodConfiguration windowAndServiceWorkerExposedMethodMethodConfiguration[] = {
         {"windowAndServiceWorkerExposedMethod", V8TestInterface5::windowAndServiceWorkerExposedMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnPrototype, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
       };
       for (const auto& methodConfig : windowAndServiceWorkerExposedMethodMethodConfiguration)
-        V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+        V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
     }
     if (executionContext && (executionContext->IsWorkerGlobalScope())) {
       const V8DOMConfiguration::MethodConfiguration workerExposedStaticMethodMethodConfiguration[] = {
         {"workerExposedStaticMethod", V8TestInterface5::workerExposedStaticMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnInterface, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
       };
       for (const auto& methodConfig : workerExposedStaticMethodMethodConfiguration)
-        V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+        V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
     }
     if (executionContext && (executionContext->IsDocument())) {
       const V8DOMConfiguration::MethodConfiguration windowExposedStaticMethodMethodConfiguration[] = {
         {"windowExposedStaticMethod", V8TestInterface5::windowExposedStaticMethodMethodCallback, 0, v8::None, V8DOMConfiguration::kOnInterface, V8DOMConfiguration::kCheckHolder, V8DOMConfiguration::kDoNotCheckAccess, V8DOMConfiguration::kHasSideEffect, V8DOMConfiguration::kAllWorlds}
       };
       for (const auto& methodConfig : windowExposedStaticMethodMethodConfiguration)
-        V8DOMConfiguration::InstallMethod(isolate, world, v8::Local<v8::Object>(), prototypeObject, interfaceObject, signature, methodConfig);
+        V8DOMConfiguration::InstallMethod(isolate, world, instanceObject, prototypeObject, interfaceObject, signature, methodConfig);
     }
   }
 }
diff --git a/third_party/blink/renderer/bindings/tests/results/modules/v8_void_callback_function_modules.cc b/third_party/blink/renderer/bindings/tests/results/modules/v8_void_callback_function_modules.cc
index c67f095..64078dd 100644
--- a/third_party/blink/renderer/bindings/tests/results/modules/v8_void_callback_function_modules.cc
+++ b/third_party/blink/renderer/bindings/tests/results/modules/v8_void_callback_function_modules.cc
@@ -53,12 +53,11 @@
       IncumbentScriptState()->GetContext());
 
   v8::Local<v8::Function> function;
-  // callback function\'s invoke:
+  // callback function's invoke:
   // step 4. If ! IsCallable(F) is false:
   //
-  // As Blink no longer supports [TreatNonObjectAsNull], there must be no such a
-  // case.
-  DCHECK(CallbackFunction()->IsFunction());
+  // No [TreatNonObjectAsNull] presents.  Must be always callable.
+  DCHECK(CallbackObject()->IsFunction());
   function = CallbackFunction();
 
   v8::Local<v8::Value> this_arg;
diff --git a/third_party/blink/renderer/controller/oom_intervention_impl.cc b/third_party/blink/renderer/controller/oom_intervention_impl.cc
index 4ddf753..e2a8b67 100644
--- a/third_party/blink/renderer/controller/oom_intervention_impl.cc
+++ b/third_party/blink/renderer/controller/oom_intervention_impl.cc
@@ -8,6 +8,7 @@
 #include "mojo/public/cpp/bindings/strong_binding.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/controller/crash_memory_metrics_reporter_impl.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/page/page.h"
 #include "third_party/blink/renderer/platform/web_task_runner.h"
 #include "third_party/blink/renderer/platform/wtf/allocator/partitions.h"
diff --git a/third_party/blink/renderer/core/dom/context_features_client_impl.cc b/third_party/blink/renderer/core/dom/context_features_client_impl.cc
index 2abcceb..bde295e4 100644
--- a/third_party/blink/renderer/core/dom/context_features_client_impl.cc
+++ b/third_party/blink/renderer/core/dom/context_features_client_impl.cc
@@ -32,6 +32,7 @@
 
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/frame/content_settings_client.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/platform/weborigin/security_origin.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/core/editing/compute_layer_selection_test.cc b/third_party/blink/renderer/core/editing/compute_layer_selection_test.cc
index becf7b2e..844f7fc6 100644
--- a/third_party/blink/renderer/core/editing/compute_layer_selection_test.cc
+++ b/third_party/blink/renderer/core/editing/compute_layer_selection_test.cc
@@ -263,4 +263,55 @@
   EXPECT_EQ(composited_selection.end.edge_bottom, gfx::Point(28, 28));
 }
 
+TEST_F(ComputeLayerSelectionTest, BlockEndBR1) {
+  // LayerSelection should be:
+  // ^test<br>
+  // |<br>
+  SetBodyContent(
+      "<div style='font: 10px/10px Ahem;'>"
+      "test<br><br></div>");
+  Element* target = GetDocument().QuerySelector("div");
+  FocusAndSelectAll(target, *target);
+  const cc::LayerSelection& layer_selection =
+      ComputeLayerSelection(Selection());
+  EXPECT_EQ(layer_selection.start.edge_top, gfx::Point(8, 8));
+  EXPECT_EQ(layer_selection.start.edge_bottom, gfx::Point(8, 18));
+  EXPECT_EQ(layer_selection.end.edge_top, gfx::Point(8, 18));
+  EXPECT_EQ(layer_selection.end.edge_bottom, gfx::Point(8, 28));
+}
+
+TEST_F(ComputeLayerSelectionTest, BlockEndBR2) {
+  // LayerSelection should be:
+  // ^test<br>
+  // |<br>
+  SetBodyContent(
+      "<div style='font: 10px/10px Ahem;'>"
+      "<div><span>test<br></span><br></div>");
+  Element* target = GetDocument().QuerySelector("div");
+  FocusAndSelectAll(target, *target);
+  const cc::LayerSelection& layer_selection =
+      ComputeLayerSelection(Selection());
+  EXPECT_EQ(layer_selection.start.edge_top, gfx::Point(8, 8));
+  EXPECT_EQ(layer_selection.start.edge_bottom, gfx::Point(8, 18));
+  EXPECT_EQ(layer_selection.end.edge_top, gfx::Point(8, 18));
+  EXPECT_EQ(layer_selection.end.edge_bottom, gfx::Point(8, 28));
+}
+
+TEST_F(ComputeLayerSelectionTest, BlockEndBR3) {
+  // LayerSelection should be:
+  // ^test<br>
+  // |<br>
+  SetBodyContent(
+      "<div style='font: 10px/10px Ahem;'>"
+      "<div><div>test<br></div><br></div>");
+  Element* target = GetDocument().QuerySelector("div");
+  FocusAndSelectAll(target, *target);
+  const cc::LayerSelection& layer_selection =
+      ComputeLayerSelection(Selection());
+  EXPECT_EQ(layer_selection.start.edge_top, gfx::Point(8, 8));
+  EXPECT_EQ(layer_selection.start.edge_bottom, gfx::Point(8, 18));
+  EXPECT_EQ(layer_selection.end.edge_top, gfx::Point(8, 18));
+  EXPECT_EQ(layer_selection.end.edge_bottom, gfx::Point(8, 28));
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/events/web_input_event_conversion.cc b/third_party/blink/renderer/core/events/web_input_event_conversion.cc
index ad20d875..9d9a9f5a 100644
--- a/third_party/blink/renderer/core/events/web_input_event_conversion.cc
+++ b/third_party/blink/renderer/core/events/web_input_event_conversion.cc
@@ -36,6 +36,7 @@
 #include "third_party/blink/renderer/core/events/mouse_event.h"
 #include "third_party/blink/renderer/core/events/touch_event.h"
 #include "third_party/blink/renderer/core/events/wheel_event.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
 #include "third_party/blink/renderer/core/input/touch.h"
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 6f4d709..9bae4474 100644
--- a/third_party/blink/renderer/core/exported/web_frame_test.cc
+++ b/third_party/blink/renderer/core/exported/web_frame_test.cc
@@ -12768,4 +12768,59 @@
             frame->GetDocument().CanonicalUrlForSharing());
 }
 
+TEST_F(WebFrameSimTest, EnterFullscreenResetScrollAndScaleState) {
+  UseAndroidSettings();
+  WebView().Resize(WebSize(490, 500));
+  WebView().EnableFakePageScaleAnimationForTesting(true);
+  WebView().GetSettings()->SetTextAutosizingEnabled(false);
+  WebView().SetDefaultPageScaleLimits(0.5f, 4);
+
+  SimRequest request("https://example.com/test.html", "text/html");
+  LoadURL("https://example.com/test.html");
+  request.Complete(R"HTML(
+      <!DOCTYPE html>
+      <style>
+        body {
+          margin: 0px;
+          width: 10000px;
+          height: 10000px;
+        }
+      </style>
+  )HTML");
+
+  Compositor().BeginFrame();
+
+  // Make the page scale and scroll with the given parameters.
+  EXPECT_EQ(0.5f, WebView().PageScaleFactor());
+  WebView().SetPageScaleFactor(2.0f);
+  WebView().MainFrameImpl()->SetScrollOffset(WebSize(94, 111));
+  WebView().SetVisualViewportOffset(WebFloatPoint(12, 20));
+  EXPECT_EQ(2.0f, WebView().PageScaleFactor());
+  EXPECT_EQ(94, WebView().MainFrameImpl()->GetScrollOffset().width);
+  EXPECT_EQ(111, WebView().MainFrameImpl()->GetScrollOffset().height);
+  EXPECT_EQ(12, WebView().VisualViewportOffset().x);
+  EXPECT_EQ(20, WebView().VisualViewportOffset().y);
+
+  LocalFrame* frame = ToLocalFrame(WebView().GetPage()->MainFrame());
+  Element* element = frame->GetDocument()->body();
+  std::unique_ptr<UserGestureIndicator> gesture =
+      Frame::NotifyUserActivation(frame);
+  Fullscreen::RequestFullscreen(*element);
+  WebView().DidEnterFullscreen();
+
+  // Page scale factor must be 1.0 during fullscreen for elements to be sized
+  // properly.
+  EXPECT_EQ(1.0f, WebView().PageScaleFactor());
+
+  // Confirm that exiting fullscreen restores back to default values.
+  WebView().DidExitFullscreen();
+  WebView().UpdateAllLifecyclePhases();
+
+  EXPECT_EQ(0.5f, WebView().PageScaleFactor());
+  EXPECT_EQ(94, WebView().MainFrameImpl()->GetScrollOffset().width);
+  EXPECT_EQ(111, WebView().MainFrameImpl()->GetScrollOffset().height);
+  EXPECT_EQ(0, WebView().VisualViewportOffset().x);
+  EXPECT_EQ(0, WebView().VisualViewportOffset().y);
+}
+
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/exported/web_view_impl.cc b/third_party/blink/renderer/core/exported/web_view_impl.cc
index 179572b2..4ab7ac2 100644
--- a/third_party/blink/renderer/core/exported/web_view_impl.cc
+++ b/third_party/blink/renderer/core/exported/web_view_impl.cc
@@ -3002,7 +3002,6 @@
   if (!client_)
     return;
 
-  fullscreen_controller_->DidUpdateMainFrameLayout();
   client_->DidUpdateMainFrameLayout();
 }
 
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 dcafda09..8dba4144 100644
--- a/third_party/blink/renderer/core/exported/web_view_test.cc
+++ b/third_party/blink/renderer/core/exported/web_view_test.cc
@@ -2330,9 +2330,9 @@
   EXPECT_GT(web_view_impl->MainFrameImpl()->GetScrollOffset().height, 2000);
 }
 
-// Tests that we restore scroll and scale *after* the fullscreen styles are
-// removed and the page is laid out. http://crbug.com/625683.
-TEST_F(WebViewTest, FullscreenResetScrollAndScaleFullscreenStyles) {
+// Tests that scroll offset modified during fullscreen is preserved when
+// exiting fullscreen.
+TEST_F(WebViewTest, FullscreenNoResetScroll) {
   RegisterMockedHttpURLLoad("fullscreen_style.html");
   WebViewImpl* web_view_impl =
       web_view_helper_.InitializeAndLoad(base_url_ + "fullscreen_style.html");
@@ -2345,128 +2345,22 @@
 
   // Enter fullscreen.
   LocalFrame* frame = web_view_impl->MainFrameImpl()->GetFrame();
-  Element* element = frame->GetDocument()->getElementById("fullscreenElement");
+  Element* element = frame->GetDocument()->documentElement();
   std::unique_ptr<UserGestureIndicator> gesture =
       Frame::NotifyUserActivation(frame);
   Fullscreen::RequestFullscreen(*element);
   web_view_impl->DidEnterFullscreen();
   web_view_impl->UpdateAllLifecyclePhases();
 
-  // Sanity-check. There should be no scrolling possible.
-  ASSERT_EQ(0, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
-  ASSERT_EQ(0, web_view_impl->MainFrameImpl()
-                   ->GetFrameView()
-                   ->LayoutViewport()
-                   ->MaximumScrollOffset()
-                   .Height());
-
-  // Confirm that after exiting and doing a layout, the scroll and scale
-  // parameters are reset. The page sets display: none on overflowing elements
-  // while in fullscreen so if we try to restore before the style and layout
-  // is applied the offsets will be clamped.
-  web_view_impl->DidExitFullscreen();
-  EXPECT_TRUE(web_view_impl->MainFrameImpl()->GetFrameView()->NeedsLayout());
-  web_view_impl->UpdateAllLifecyclePhases();
-
-  EXPECT_EQ(2000, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
-}
-
-// Tests that exiting and immediately reentering fullscreen doesn't cause the
-// scroll and scale restoration to occur when we enter fullscreen again.
-TEST_F(WebViewTest, FullscreenResetScrollAndScaleExitAndReenter) {
-  RegisterMockedHttpURLLoad("fullscreen_style.html");
-  WebViewImpl* web_view_impl =
-      web_view_helper_.InitializeAndLoad(base_url_ + "fullscreen_style.html");
-  web_view_impl->Resize(WebSize(800, 600));
-  web_view_impl->UpdateAllLifecyclePhases();
-
-  // Scroll the page down.
-  web_view_impl->MainFrameImpl()->SetScrollOffset(WebSize(0, 2000));
+  // Assert the scroll position on the document element doesn't change.
   ASSERT_EQ(2000, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
 
-  // Enter fullscreen.
-  LocalFrame* frame = web_view_impl->MainFrameImpl()->GetFrame();
-  Element* element = frame->GetDocument()->getElementById("fullscreenElement");
-  std::unique_ptr<UserGestureIndicator> gesture =
-      Frame::NotifyUserActivation(frame);
-  Fullscreen::RequestFullscreen(*element);
-  web_view_impl->DidEnterFullscreen();
-  web_view_impl->UpdateAllLifecyclePhases();
+  web_view_impl->MainFrameImpl()->SetScrollOffset(WebSize(0, 2100));
 
-  // Sanity-check. There should be no scrolling possible.
-  ASSERT_EQ(0, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
-  ASSERT_EQ(0, web_view_impl->MainFrameImpl()
-                   ->GetFrameView()
-                   ->LayoutViewport()
-                   ->MaximumScrollOffset()
-                   .Height());
-
-  // Exit and, without performing a layout, reenter fullscreen again. We
-  // shouldn't try to restore the scroll and scale values when we layout to
-  // enter fullscreen.
-  web_view_impl->DidExitFullscreen();
-  Fullscreen::RequestFullscreen(*element);
-  web_view_impl->DidEnterFullscreen();
-  web_view_impl->UpdateAllLifecyclePhases();
-
-  // Sanity-check. There should be no scrolling possible.
-  ASSERT_EQ(0, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
-  ASSERT_EQ(0, web_view_impl->MainFrameImpl()
-                   ->GetFrameView()
-                   ->LayoutViewport()
-                   ->MaximumScrollOffset()
-                   .Height());
-
-  // When we exit now, we should restore the original scroll value.
   web_view_impl->DidExitFullscreen();
   web_view_impl->UpdateAllLifecyclePhases();
 
-  EXPECT_EQ(2000, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
-}
-
-TEST_F(WebViewTest, EnterFullscreenResetScrollAndScaleState) {
-  RegisterMockedHttpURLLoad("200-by-300.html");
-  WebViewImpl* web_view_impl =
-      web_view_helper_.InitializeAndLoad(base_url_ + "200-by-300.html");
-  web_view_impl->Resize(WebSize(100, 150));
-  web_view_impl->UpdateAllLifecyclePhases();
-  EXPECT_EQ(0, web_view_impl->MainFrameImpl()->GetScrollOffset().width);
-  EXPECT_EQ(0, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
-
-  // Make the page scale and scroll with the given paremeters.
-  web_view_impl->SetPageScaleFactor(2.0f);
-  web_view_impl->MainFrameImpl()->SetScrollOffset(WebSize(94, 111));
-  web_view_impl->SetVisualViewportOffset(WebFloatPoint(12, 20));
-  EXPECT_EQ(2.0f, web_view_impl->PageScaleFactor());
-  EXPECT_EQ(94, web_view_impl->MainFrameImpl()->GetScrollOffset().width);
-  EXPECT_EQ(111, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
-  EXPECT_EQ(12, web_view_impl->VisualViewportOffset().x);
-  EXPECT_EQ(20, web_view_impl->VisualViewportOffset().y);
-
-  LocalFrame* frame = web_view_impl->MainFrameImpl()->GetFrame();
-  Element* element = frame->GetDocument()->body();
-  std::unique_ptr<UserGestureIndicator> gesture =
-      Frame::NotifyUserActivation(frame);
-  Fullscreen::RequestFullscreen(*element);
-  web_view_impl->DidEnterFullscreen();
-
-  // Page scale factor must be 1.0 during fullscreen for elements to be sized
-  // properly.
-  EXPECT_EQ(1.0f, web_view_impl->PageScaleFactor());
-
-  // Make sure fullscreen nesting doesn't disrupt scroll/scale saving.
-  Element* other_element = frame->GetDocument()->getElementById("content");
-  Fullscreen::RequestFullscreen(*other_element);
-
-  // Confirm that exiting fullscreen restores the parameters.
-  web_view_impl->DidExitFullscreen();
-  web_view_impl->UpdateAllLifecyclePhases();
-
-  EXPECT_EQ(2.0f, web_view_impl->PageScaleFactor());
-  EXPECT_EQ(94, web_view_impl->MainFrameImpl()->GetScrollOffset().width);
-  EXPECT_EQ(111, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
-  EXPECT_EQ(12, web_view_impl->VisualViewportOffset().x);
-  EXPECT_EQ(20, web_view_impl->VisualViewportOffset().y);
+  EXPECT_EQ(2100, web_view_impl->MainFrameImpl()->GetScrollOffset().height);
 }
 
 class PrintWebViewClient : public FrameTestHelpers::TestWebViewClient {
diff --git a/third_party/blink/renderer/core/fetch/fetch_header_list.cc b/third_party/blink/renderer/core/fetch/fetch_header_list.cc
index 2839f94..7bacec12 100644
--- a/third_party/blink/renderer/core/fetch/fetch_header_list.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_header_list.cc
@@ -128,13 +128,6 @@
   header_list_.clear();
 }
 
-bool FetchHeaderList::ContainsNonCORSSafelistedHeader() const {
-  return std::any_of(
-      header_list_.cbegin(), header_list_.cend(), [](const Header& header) {
-        return !CORS::IsCORSSafelistedHeader(header.first, header.second);
-      });
-}
-
 Vector<FetchHeaderList::Header> FetchHeaderList::SortAndCombine() const {
   // https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine
   // "To sort and combine a header list (|list|), run these steps:
diff --git a/third_party/blink/renderer/core/fetch/fetch_header_list.h b/third_party/blink/renderer/core/fetch/fetch_header_list.h
index e84f0985..7cd863c 100644
--- a/third_party/blink/renderer/core/fetch/fetch_header_list.h
+++ b/third_party/blink/renderer/core/fetch/fetch_header_list.h
@@ -41,7 +41,6 @@
   bool Has(const String&) const;
   void ClearList();
 
-  bool ContainsNonCORSSafelistedHeader() const;
   Vector<Header> SortAndCombine() const;
 
   const std::multimap<String, String, ByteCaseInsensitiveCompare>& List()
@@ -67,8 +66,7 @@
   // This would cause FetchHeaderList::size() to have to manually
   // iterate through all keys and vectors in the HashMap. Similarly,
   // list() would require callers to manually iterate through the
-  // HashMap's keys and value vector, and so would
-  // ContainsNonCORSSafelistedHeader().
+  // HashMap's keys and value vector.
   std::multimap<String, String, ByteCaseInsensitiveCompare> header_list_;
 };
 
diff --git a/third_party/blink/renderer/core/fetch/fetch_header_list_test.cc b/third_party/blink/renderer/core/fetch/fetch_header_list_test.cc
index e23bc70..05b0f54 100644
--- a/third_party/blink/renderer/core/fetch/fetch_header_list_test.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_header_list_test.cc
@@ -117,26 +117,6 @@
   EXPECT_FALSE(headerList->Has("X-Bar"));
 }
 
-TEST(FetchHeaderListTest, ContainsNonCORSSafelistedHeader) {
-  FetchHeaderList* headerList = FetchHeaderList::Create();
-  EXPECT_FALSE(headerList->ContainsNonCORSSafelistedHeader());
-
-  headerList->Append("Host", "foobar");
-  headerList->Append("X-Foo", "bar");
-  EXPECT_TRUE(headerList->ContainsNonCORSSafelistedHeader());
-
-  headerList->ClearList();
-  headerList->Append("ConTenT-TyPe", "text/plain");
-  headerList->Append("content-type", "application/xml");
-  headerList->Append("X-Foo", "bar");
-  EXPECT_TRUE(headerList->ContainsNonCORSSafelistedHeader());
-
-  headerList->ClearList();
-  headerList->Append("ConTenT-TyPe", "multipart/form-data");
-  headerList->Append("Accept", "xyz");
-  EXPECT_FALSE(headerList->ContainsNonCORSSafelistedHeader());
-}
-
 TEST(FetchHeaderListTest, SortAndCombine) {
   FetchHeaderList* headerList = FetchHeaderList::Create();
   EXPECT_TRUE(headerList->SortAndCombine().IsEmpty());
diff --git a/third_party/blink/renderer/core/fetch/fetch_manager.cc b/third_party/blink/renderer/core/fetch/fetch_manager.cc
index 9cc875b..9a2df6fc 100644
--- a/third_party/blink/renderer/core/fetch/fetch_manager.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_manager.cc
@@ -858,27 +858,9 @@
   request.SetUseStreamOnResponse(true);
   request.SetExternalRequestStateFromRequestorAddressSpace(
       execution_context_->GetSecurityContext().AddressSpace());
+  request.SetReferrerString(fetch_request_data_->ReferrerString());
+  request.SetReferrerPolicy(fetch_request_data_->GetReferrerPolicy());
 
-  // "2. Append `Referer`/empty byte sequence, if |HTTPRequest|'s |referrer|
-  // is none, and `Referer`/|HTTPRequest|'s referrer, serialized and utf-8
-  // encoded, otherwise, to HTTPRequest's header list.
-  //
-  // The following code also invokes "determine request's referrer" which is
-  // written in "Main fetch" operation.
-  const ReferrerPolicy referrer_policy =
-      fetch_request_data_->GetReferrerPolicy() == kReferrerPolicyDefault
-          ? execution_context_->GetReferrerPolicy()
-          : fetch_request_data_->GetReferrerPolicy();
-  const String referrer_string =
-      fetch_request_data_->ReferrerString() == Referrer::ClientReferrerString()
-          ? execution_context_->OutgoingReferrer()
-          : fetch_request_data_->ReferrerString();
-  // Note that generateReferrer generates |no-referrer| from |no-referrer|
-  // referrer string (i.e. String()).
-  // TODO(domfarolino): Can we use ResourceRequest's SetReferrerString() and
-  // SetReferrerPolicy() instead of calling SetHTTPReferrer()?
-  request.SetHTTPReferrer(SecurityPolicy::GenerateReferrer(
-      referrer_policy, fetch_request_data_->Url(), referrer_string));
   request.SetSkipServiceWorker(is_isolated_world_);
 
   if (fetch_request_data_->Keepalive()) {
diff --git a/third_party/blink/renderer/core/fetch/headers.cc b/third_party/blink/renderer/core/fetch/headers.cc
index fc60cc3c..a581c74 100644
--- a/third_party/blink/renderer/core/fetch/headers.cc
+++ b/third_party/blink/renderer/core/fetch/headers.cc
@@ -98,9 +98,9 @@
   if (guard_ == kRequestGuard && CORS::IsForbiddenHeaderName(name))
     return;
   // "5. Otherwise, if guard is |request-no-CORS| and |name|/|value| is not a
-  //     CORS-safelisted header, return."
+  //     no-CORS-safelisted header, return."
   if (guard_ == kRequestNoCORSGuard &&
-      !CORS::IsCORSSafelistedHeader(name, normalized_value)) {
+      !CORS::IsNoCORSSafelistedHeader(name, normalized_value)) {
     return;
   }
   // "6. Otherwise, if guard is |response| and |name| is a forbidden response
@@ -130,9 +130,9 @@
   if (guard_ == kRequestGuard && CORS::IsForbiddenHeaderName(name))
     return;
   // "4. Otherwise, if guard is |request-no-CORS| and |name|/`invalid` is not
-  //     a CORS-safelisted header, return."
+  //     a no-CORS-safelisted header, return."
   if (guard_ == kRequestNoCORSGuard &&
-      !CORS::IsCORSSafelistedHeader(name, "invalid")) {
+      !CORS::IsNoCORSSafelistedHeader(name, "invalid")) {
     return;
   }
   // "5. Otherwise, if guard is |response| and |name| is a forbidden response
@@ -198,9 +198,9 @@
   if (guard_ == kRequestGuard && CORS::IsForbiddenHeaderName(name))
     return;
   // "5. Otherwise, if guard is |request-no-CORS| and |name|/|value| is not a
-  //     CORS-safelisted header, return."
+  //     no-CORS-safelisted header, return."
   if (guard_ == kRequestNoCORSGuard &&
-      !CORS::IsCORSSafelistedHeader(name, normalized_value)) {
+      !CORS::IsNoCORSSafelistedHeader(name, normalized_value)) {
     return;
   }
   // "6. Otherwise, if guard is |response| and |name| is a forbidden response
diff --git a/third_party/blink/renderer/core/frame/fullscreen_controller.cc b/third_party/blink/renderer/core/frame/fullscreen_controller.cc
index a64cf52..1a86366 100644
--- a/third_party/blink/renderer/core/frame/fullscreen_controller.cc
+++ b/third_party/blink/renderer/core/frame/fullscreen_controller.cc
@@ -111,10 +111,7 @@
 
   UpdatePageScaleConstraints(true);
 
-  // We need to wait until style and layout are updated in order to properly
-  // restore scroll offsets since content may not be overflowing in the same way
-  // until they are.
-  state_ = State::kNeedsScrollAndScaleRestore;
+  state_ = State::kInitial;
 
   // Notify the topmost local frames that we have exited fullscreen.
   // |Fullscreen::DidExitFullscreen()| will take care of descendant frames.
@@ -159,13 +156,6 @@
   // restore a previous set. This can happen if we exit and quickly reenter
   // fullscreen without performing a layout.
   if (state_ == State::kInitial) {
-    // TODO(dtapuska): Remove these fields https://crbug.com/878773
-    initial_page_scale_factor_ = web_view_base_->PageScaleFactor();
-    initial_scroll_offset_ =
-        web_view_base_->MainFrame()->IsWebLocalFrame()
-            ? web_view_base_->MainFrame()->ToWebLocalFrame()->GetScrollOffset()
-            : WebSize();
-    initial_visual_viewport_offset_ = web_view_base_->VisualViewportOffset();
     initial_background_color_override_enabled_ =
         web_view_base_->BackgroundColorOverrideEnabled();
     initial_background_color_override_ =
@@ -178,8 +168,7 @@
   if (state_ == State::kEnteringFullscreen)
     return;
 
-  DCHECK(state_ == State::kInitial ||
-         state_ == State::kNeedsScrollAndScaleRestore);
+  DCHECK(state_ == State::kInitial);
   blink::WebFullscreenOptions blink_options;
   // Only clone options if the feature is enabled.
   if (RuntimeEnabledFeatures::FullscreenOptionsEnabled())
@@ -260,25 +249,11 @@
   UpdatePageScaleConstraints(false);
 }
 
-void FullscreenController::DidUpdateMainFrameLayout() {
-  if (state_ != State::kNeedsScrollAndScaleRestore)
-    return;
-
-  web_view_base_->SetPageScaleFactor(initial_page_scale_factor_);
-  if (web_view_base_->MainFrame()->IsWebLocalFrame()) {
-    web_view_base_->MainFrame()->ToWebLocalFrame()->SetScrollOffset(
-        WebSize(initial_scroll_offset_));
-  }
-  web_view_base_->SetVisualViewportOffset(initial_visual_viewport_offset_);
-  // Background color override was already restored when
-  // FullscreenElementChanged([..], nullptr) was called while exiting.
-
-  state_ = State::kInitial;
-}
-
-void FullscreenController::UpdatePageScaleConstraints(bool remove_constraints) {
+void FullscreenController::UpdatePageScaleConstraints(bool reset_constraints) {
   PageScaleConstraints fullscreen_constraints;
-  if (!remove_constraints) {
+  if (reset_constraints) {
+    web_view_base_->GetPageScaleConstraintsSet().SetNeedsReset(true);
+  } else {
     fullscreen_constraints = PageScaleConstraints(1.0, 1.0, 1.0);
     fullscreen_constraints.layout_size = FloatSize(web_view_base_->Size());
   }
diff --git a/third_party/blink/renderer/core/frame/fullscreen_controller.h b/third_party/blink/renderer/core/frame/fullscreen_controller.h
index 986b7ef..01f3b82 100644
--- a/third_party/blink/renderer/core/frame/fullscreen_controller.h
+++ b/third_party/blink/renderer/core/frame/fullscreen_controller.h
@@ -72,37 +72,24 @@
 
   void UpdateSize();
 
-  void DidUpdateMainFrameLayout();
-
  protected:
   explicit FullscreenController(WebViewImpl*);
 
  private:
-  void UpdatePageScaleConstraints(bool remove_constraints);
+  void UpdatePageScaleConstraints(bool reset_constraints);
   void RestoreBackgroundColorOverride();
 
   WebViewImpl* web_view_base_;
 
-  // State is used to avoid unnecessary enter/exit requests, and to restore the
-  // initial*_ after the first layout upon exiting fullscreen. Typically, the
-  // state goes through every state from Initial to NeedsScrollAndScaleRestore
-  // and then back to Initial, but the are two exceptions:
-  //  1. DidExitFullscreen() can transition from any non-Initial state to
-  //     NeedsScrollAndScaleRestore, in case of a browser-intiated exit.
-  //  2. EnterFullscreen() can transition from NeedsScrollAndScaleRestore to
-  //     EnteringFullscreen, in case of a quick exit+enter.
+  // State is used to avoid unnecessary enter/exit requests.
   enum class State {
     kInitial,
     kEnteringFullscreen,
     kFullscreen,
     kExitingFullscreen,
-    kNeedsScrollAndScaleRestore
   };
   State state_ = State::kInitial;
 
-  float initial_page_scale_factor_ = 0.0f;
-  IntSize initial_scroll_offset_;
-  FloatPoint initial_visual_viewport_offset_;
   bool initial_background_color_override_enabled_ = false;
   RGBA32 initial_background_color_override_ = Color::kTransparent;
 
diff --git a/third_party/blink/renderer/core/frame/link_highlights.cc b/third_party/blink/renderer/core/frame/link_highlights.cc
index 1f4cc617..e0a7b06 100644
--- a/third_party/blink/renderer/core/frame/link_highlights.cc
+++ b/third_party/blink/renderer/core/frame/link_highlights.cc
@@ -10,6 +10,7 @@
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/public/platform/web_layer_tree_view.h"
 #include "third_party/blink/renderer/core/dom/node.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/layout/layout_object.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
 #include "third_party/blink/renderer/core/page/page.h"
diff --git a/third_party/blink/renderer/core/frame/platform_event_controller.cc b/third_party/blink/renderer/core/frame/platform_event_controller.cc
index 3c8fa1d..aa45285 100644
--- a/third_party/blink/renderer/core/frame/platform_event_controller.cc
+++ b/third_party/blink/renderer/core/frame/platform_event_controller.cc
@@ -10,9 +10,7 @@
 namespace blink {
 
 PlatformEventController::PlatformEventController(Document* document)
-    : PageVisibilityObserver(document && document->GetFrame()
-                                 ? document->GetFrame()->GetPage()
-                                 : nullptr),
+    : PageVisibilityObserver(document ? document->GetPage() : nullptr),
       has_event_listener_(false),
       is_active_(false),
       document_(document) {}
diff --git a/third_party/blink/renderer/core/frame/resize_viewport_anchor.cc b/third_party/blink/renderer/core/frame/resize_viewport_anchor.cc
index c2d8000..1a805ce 100644
--- a/third_party/blink/renderer/core/frame/resize_viewport_anchor.cc
+++ b/third_party/blink/renderer/core/frame/resize_viewport_anchor.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/frame/resize_viewport_anchor.h"
 
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/frame/root_frame_viewport.h"
 #include "third_party/blink/renderer/core/frame/visual_viewport.h"
diff --git a/third_party/blink/renderer/core/frame/rotation_viewport_anchor_test.cc b/third_party/blink/renderer/core/frame/rotation_viewport_anchor_test.cc
index 391187a..0bc00725 100644
--- a/third_party/blink/renderer/core/frame/rotation_viewport_anchor_test.cc
+++ b/third_party/blink/renderer/core/frame/rotation_viewport_anchor_test.cc
@@ -4,6 +4,7 @@
 
 #include "build/build_config.h"
 #include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
 #include "third_party/blink/renderer/core/testing/sim/sim_request.h"
 #include "third_party/blink/renderer/core/testing/sim/sim_test.h"
diff --git a/third_party/blink/renderer/core/fullscreen/element_fullscreen.cc b/third_party/blink/renderer/core/fullscreen/element_fullscreen.cc
index 2f38e20..e31e4848 100644
--- a/third_party/blink/renderer/core/fullscreen/element_fullscreen.cc
+++ b/third_party/blink/renderer/core/fullscreen/element_fullscreen.cc
@@ -18,7 +18,9 @@
 }
 
 void ElementFullscreen::webkitRequestFullscreen(Element& element) {
-  webkitRequestFullscreen(element, FullscreenOptions());
+  FullscreenOptions options;
+  options.setNavigationUI("hide");
+  webkitRequestFullscreen(element, options);
 }
 
 void ElementFullscreen::webkitRequestFullscreen(
diff --git a/third_party/blink/renderer/core/html/anchor_element_metrics_test.cc b/third_party/blink/renderer/core/html/anchor_element_metrics_test.cc
index a9baf18..e5a6bef 100644
--- a/third_party/blink/renderer/core/html/anchor_element_metrics_test.cc
+++ b/third_party/blink/renderer/core/html/anchor_element_metrics_test.cc
@@ -8,6 +8,8 @@
 #include "base/test/scoped_feature_list.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/common/features.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
+#include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/html/html_anchor_element.h"
 #include "third_party/blink/renderer/core/html/html_iframe_element.h"
 #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
diff --git a/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.cc b/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.cc
index 3328396a..74db3c1 100644
--- a/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.cc
+++ b/third_party/blink/renderer/core/html/forms/chooser_only_temporal_input_type_view.cc
@@ -28,6 +28,7 @@
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
 #include "third_party/blink/renderer/core/dom/shadow_root.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
 #include "third_party/blink/renderer/core/html/html_div_element.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
diff --git a/third_party/blink/renderer/core/html/media/autoplay_uma_helper.cc b/third_party/blink/renderer/core/html/media/autoplay_uma_helper.cc
index c3e033ed..5f71c91 100644
--- a/third_party/blink/renderer/core/html/media/autoplay_uma_helper.cc
+++ b/third_party/blink/renderer/core/html/media/autoplay_uma_helper.cc
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/element_visibility_observer.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/settings.h"
 #include "third_party/blink/renderer/core/frame/use_counter.h"
 #include "third_party/blink/renderer/core/html/media/autoplay_policy.h"
diff --git a/third_party/blink/renderer/core/html/media/html_video_element.cc b/third_party/blink/renderer/core/html/media/html_video_element.cc
index 57473bc6..73366dd 100644
--- a/third_party/blink/renderer/core/html/media/html_video_element.cc
+++ b/third_party/blink/renderer/core/html/media/html_video_element.cc
@@ -459,7 +459,9 @@
 
 void HTMLVideoElement::webkitEnterFullscreen() {
   if (!IsFullscreen()) {
-    Fullscreen::RequestFullscreen(*this, FullscreenOptions(),
+    FullscreenOptions options;
+    options.setNavigationUI("hide");
+    Fullscreen::RequestFullscreen(*this, options,
                                   Fullscreen::RequestType::kPrefixed);
   }
 }
diff --git a/third_party/blink/renderer/core/input/event_handler.cc b/third_party/blink/renderer/core/input/event_handler.cc
index 998c32a57..c25c6f9 100644
--- a/third_party/blink/renderer/core/input/event_handler.cc
+++ b/third_party/blink/renderer/core/input/event_handler.cc
@@ -964,11 +964,11 @@
   event_result = DispatchMousePointerEvent(
       WebInputEvent::kPointerMove, mev.InnerNode(), mev.CanvasRegionId(),
       mev.Event(), coalesced_events);
+  // TODO(crbug.com/346473): Since there is no default action for the mousemove
+  // event we should consider doing drag&drop even when js cancels the
+  // mouse move event.
   // https://w3c.github.io/uievents/#event-type-mousemove
-  // Since there is no default action for the mousemove event issue a
-  // mouse dragged event irrespective of whether the event is cancelled.
-  if (event_result != WebInputEventResult::kNotHandled &&
-      event_result != WebInputEventResult::kHandledApplication)
+  if (event_result != WebInputEventResult::kNotHandled)
     return event_result;
 
   return mouse_event_manager_->HandleMouseDraggedEvent(mev);
diff --git a/third_party/blink/renderer/core/inspector/thread_debugger.cc b/third_party/blink/renderer/core/inspector/thread_debugger.cc
index a8256bca..790b00d 100644
--- a/third_party/blink/renderer/core/inspector/thread_debugger.cc
+++ b/third_party/blink/renderer/core/inspector/thread_debugger.cc
@@ -14,7 +14,6 @@
 #include "third_party/blink/renderer/bindings/core/v8/v8_event.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_event_listener_helper.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_event_listener_info.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_event_listener_or_event_handler.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_html_all_collection.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_html_collection.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_node.h"
diff --git a/third_party/blink/renderer/core/layout/layout_block.h b/third_party/blink/renderer/core/layout/layout_block.h
index d321a9b1..380d4eb 100644
--- a/third_party/blink/renderer/core/layout/layout_block.h
+++ b/third_party/blink/renderer/core/layout/layout_block.h
@@ -304,6 +304,13 @@
   void CheckPositionedObjectsNeedLayout();
 #endif
 
+  // This method returns the size that percentage logical heights should
+  // resolve against *if* this LayoutBlock is the containing block for the
+  // percentage calculation.
+  //
+  // A version of this function without the above restriction, (that will walk
+  // the ancestor chain in quirks mode), see:
+  // LayoutBox::ContainingBlockLogicalHeightForPercentageResolution
   LayoutUnit AvailableLogicalHeightForPercentageComputation() const;
   bool HasDefiniteLogicalHeight() const;
 
diff --git a/third_party/blink/renderer/core/layout/layout_box.cc b/third_party/blink/renderer/core/layout/layout_box.cc
index ea4f625..6e61383 100644
--- a/third_party/blink/renderer/core/layout/layout_box.cc
+++ b/third_party/blink/renderer/core/layout/layout_box.cc
@@ -3402,8 +3402,9 @@
          containing_block->StyleRef().LogicalHeight().IsAuto();
 }
 
-LayoutUnit LayoutBox::ComputePercentageLogicalHeight(
-    const Length& height) const {
+LayoutUnit LayoutBox::ContainingBlockLogicalHeightForPercentageResolution(
+    LayoutBlock** out_cb,
+    bool* out_skipped_auto_height_containing_block) const {
   LayoutBlock* cb = ContainingBlock();
   const LayoutBox* containing_block_child = this;
   bool skipped_auto_height_containing_block = false;
@@ -3419,7 +3420,14 @@
     containing_block_child = cb;
     cb = cb->ContainingBlock();
   }
-  cb->AddPercentHeightDescendant(const_cast<LayoutBox*>(this));
+
+  if (out_cb)
+    *out_cb = cb;
+
+  if (out_skipped_auto_height_containing_block) {
+    *out_skipped_auto_height_containing_block =
+        skipped_auto_height_containing_block;
+  }
 
   LayoutUnit available_height(-1);
   if (IsHorizontalWritingMode() != cb->IsHorizontalWritingMode()) {
@@ -3465,7 +3473,25 @@
   if (IsTable() && IsOutOfFlowPositioned())
     available_height += cb->PaddingLogicalHeight();
 
+  return available_height;
+}
+
+LayoutUnit LayoutBox::ComputePercentageLogicalHeight(
+    const Length& height) const {
+  bool skipped_auto_height_containing_block = false;
+  LayoutBlock* cb = nullptr;
+  LayoutUnit available_height =
+      ContainingBlockLogicalHeightForPercentageResolution(
+          &cb, &skipped_auto_height_containing_block);
+
+  DCHECK(cb);
+  cb->AddPercentHeightDescendant(const_cast<LayoutBox*>(this));
+
+  if (available_height == -1)
+    return available_height;
+
   LayoutUnit result = ValueForLength(height, available_height);
+
   // |OverrideLogicalHeight| is the maximum height made available by the
   // cell to its percent height children when we decide they can determine the
   // height of the cell. If the percent height child is box-sizing:content-box
diff --git a/third_party/blink/renderer/core/layout/layout_box.h b/third_party/blink/renderer/core/layout/layout_box.h
index 7bf7186d..f8dd20f 100644
--- a/third_party/blink/renderer/core/layout/layout_box.h
+++ b/third_party/blink/renderer/core/layout/layout_box.h
@@ -1012,6 +1012,16 @@
   virtual LayoutUnit ComputeReplacedLogicalHeight(
       LayoutUnit estimated_used_width = LayoutUnit()) const;
 
+  // Returns the size that percentage logical heights of this box should be
+  // resolved against. This function will walk the ancestor chain of this
+  // object to determine this size.
+  //  - out_cb returns the LayoutBlock which provided the size.
+  //  - out_skipped_auto_height_containing_block returns if any auto height
+  //    blocks were skipped to obtain out_cb.
+  LayoutUnit ContainingBlockLogicalHeightForPercentageResolution(
+      LayoutBlock** out_cb = nullptr,
+      bool* out_skipped_auto_height_containing_block = nullptr) const;
+
   bool PercentageLogicalHeightIsResolvable() const;
   LayoutUnit ComputePercentageLogicalHeight(const Length& height) const;
 
diff --git a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
index 4b0ca0d4..5e32e73 100644
--- a/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
+++ b/third_party/blink/renderer/core/layout/ng/ng_constraint_space.cc
@@ -92,8 +92,7 @@
     } else if (box.ContainingBlock()) {
       if (parallel_containing_block) {
         available_logical_height =
-            box.ContainingBlock()
-                ->AvailableLogicalHeightForPercentageComputation();
+            box.ContainingBlockLogicalHeightForPercentageResolution();
       } else {
         available_logical_height = box.ContainingBlockLogicalWidthForContent();
       }
diff --git a/third_party/blink/renderer/core/loader/document_loader.cc b/third_party/blink/renderer/core/loader/document_loader.cc
index 50296b8..8a70169a 100644
--- a/third_party/blink/renderer/core/loader/document_loader.cc
+++ b/third_party/blink/renderer/core/loader/document_loader.cc
@@ -968,6 +968,9 @@
     document->ParseAndSetReferrerPolicy(referrer_policy_header);
   }
 
+  if (response_.IsSignedExchangeInnerResponse())
+    UseCounter::Count(*document, WebFeature::kSignedExchangeInnerResponse);
+
   GetLocalFrameClient().DidCreateNewDocument();
 }
 
diff --git a/third_party/blink/renderer/core/loader/threadable_loader.cc b/third_party/blink/renderer/core/loader/threadable_loader.cc
index 15acdfc..040bd2e 100644
--- a/third_party/blink/renderer/core/loader/threadable_loader.cc
+++ b/third_party/blink/renderer/core/loader/threadable_loader.cc
@@ -79,20 +79,8 @@
 // Fetch API Spec: https://fetch.spec.whatwg.org/#cors-preflight-fetch-0
 AtomicString CreateAccessControlRequestHeadersHeader(
     const HTTPHeaderMap& headers) {
-  Vector<String> filtered_headers;
-  for (const auto& header : headers) {
-    // Exclude CORS-safelisted headers.
-    if (CORS::IsCORSSafelistedHeader(header.key, header.value))
-      continue;
-    // Calling a deprecated function, but eventually this function,
-    // |CreateAccessControlRequestHeadersHeader| will be removed.
-    // When the request is from a Worker, referrer header was added by
-    // WorkerThreadableLoader. But it should not be added to
-    // Access-Control-Request-Headers header.
-    if (DeprecatedEqualIgnoringCase(header.key, "referer"))
-      continue;
-    filtered_headers.push_back(header.key.DeprecatedLower());
-  }
+  Vector<String> filtered_headers = CORS::CORSUnsafeRequestHeaderNames(headers);
+
   if (!filtered_headers.size())
     return g_null_atom;
 
@@ -176,9 +164,7 @@
   preflight_request->SetFetchCredentialsMode(
       network::mojom::FetchCredentialsMode::kOmit);
   preflight_request->SetSkipServiceWorker(true);
-  // TODO(domfarolino): Use ReferrerString() once https://crbug.com/850813 is
-  // closed and we stop storing the referrer string as a `Referer` header.
-  preflight_request->SetReferrerString(request.HttpReferrer());
+  preflight_request->SetReferrerString(request.ReferrerString());
   preflight_request->SetReferrerPolicy(request.GetReferrerPolicy());
 
   if (request.IsExternalRequest()) {
diff --git a/third_party/blink/renderer/core/messaging/blink_cloneable_message.typemap b/third_party/blink/renderer/core/messaging/blink_cloneable_message.typemap
index dd0336a..87b9d16 100644
--- a/third_party/blink/renderer/core/messaging/blink_cloneable_message.typemap
+++ b/third_party/blink/renderer/core/messaging/blink_cloneable_message.typemap
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-mojom = "//third_party/blink/public/mojom/message_port/message_port.mojom"
+mojom = "//third_party/blink/public/mojom/messaging/message_port.mojom"
 public_headers =
     [ "//third_party/blink/renderer/core/messaging/blink_cloneable_message.h" ]
 traits_headers = [ "//third_party/blink/renderer/core/messaging/blink_cloneable_message_struct_traits.h" ]
diff --git a/third_party/blink/renderer/core/messaging/blink_cloneable_message_struct_traits.h b/third_party/blink/renderer/core/messaging/blink_cloneable_message_struct_traits.h
index f74cfcb..d976534c 100644
--- a/third_party/blink/renderer/core/messaging/blink_cloneable_message_struct_traits.h
+++ b/third_party/blink/renderer/core/messaging/blink_cloneable_message_struct_traits.h
@@ -9,7 +9,7 @@
 #include "mojo/public/cpp/base/unguessable_token_mojom_traits.h"
 #include "mojo/public/cpp/bindings/array_traits_wtf_vector.h"
 #include "mojo/public/cpp/bindings/string_traits_wtf.h"
-#include "third_party/blink/public/mojom/message_port/message_port.mojom-blink.h"
+#include "third_party/blink/public/mojom/messaging/message_port.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/messaging/blink_cloneable_message.h"
diff --git a/third_party/blink/renderer/core/messaging/blink_transferable_message.h b/third_party/blink/renderer/core/messaging/blink_transferable_message.h
index b1ac191..1e6fce8 100644
--- a/third_party/blink/renderer/core/messaging/blink_transferable_message.h
+++ b/third_party/blink/renderer/core/messaging/blink_transferable_message.h
@@ -6,9 +6,9 @@
 #define THIRD_PARTY_BLINK_RENDERER_CORE_MESSAGING_BLINK_TRANSFERABLE_MESSAGE_H_
 
 #include "base/macros.h"
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
-#include "third_party/blink/public/common/message_port/transferable_message.h"
-#include "third_party/blink/public/mojom/message_port/user_activation_snapshot.mojom-blink.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
+#include "third_party/blink/public/common/messaging/transferable_message.h"
+#include "third_party/blink/public/mojom/messaging/user_activation_snapshot.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/messaging/blink_cloneable_message.h"
diff --git a/third_party/blink/renderer/core/messaging/blink_transferable_message.typemap b/third_party/blink/renderer/core/messaging/blink_transferable_message.typemap
index a7ab5d3..e0e5567f 100644
--- a/third_party/blink/renderer/core/messaging/blink_transferable_message.typemap
+++ b/third_party/blink/renderer/core/messaging/blink_transferable_message.typemap
@@ -2,7 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
-mojom = "//third_party/blink/public/mojom/message_port/message_port.mojom"
+mojom = "//third_party/blink/public/mojom/messaging/message_port.mojom"
 public_headers = [
   "//third_party/blink/renderer/core/messaging/blink_transferable_message.h",
 ]
diff --git a/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits.cc b/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits.cc
index 06b904b..1b5ec721 100644
--- a/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits.cc
+++ b/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits.cc
@@ -5,7 +5,7 @@
 #include "third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits.h"
 
 #include "mojo/public/cpp/base/big_buffer_mojom_traits.h"
-#include "third_party/blink/public/mojom/message_port/message_port.mojom-blink.h"
+#include "third_party/blink/public/mojom/messaging/message_port.mojom-blink.h"
 #include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 
diff --git a/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits.h b/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits.h
index a2f966f..0523e811 100644
--- a/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits.h
+++ b/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits.h
@@ -7,8 +7,8 @@
 
 #include "mojo/public/cpp/bindings/array_traits_wtf_vector.h"
 #include "skia/public/interfaces/bitmap_skbitmap_struct_traits.h"
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
-#include "third_party/blink/public/mojom/message_port/message_port.mojom-blink.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
+#include "third_party/blink/public/mojom/messaging/message_port.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/messaging/blink_cloneable_message_struct_traits.h"
diff --git a/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits_test.cc b/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits_test.cc
index e7a491b..1f31017 100644
--- a/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits_test.cc
+++ b/third_party/blink/renderer/core/messaging/blink_transferable_message_struct_traits_test.cc
@@ -8,8 +8,8 @@
 #include "base/memory/scoped_refptr.h"
 #include "mojo/public/cpp/base/big_buffer_mojom_traits.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
-#include "third_party/blink/public/mojom/message_port/message_port.mojom-blink.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
+#include "third_party/blink/public/mojom/messaging/message_port.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
 #include "third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.h"
 #include "third_party/blink/renderer/bindings/core/v8/v8_array_buffer.h"
diff --git a/third_party/blink/renderer/core/messaging/message_port.h b/third_party/blink/renderer/core/messaging/message_port.h
index cf609e7b2..c983d11 100644
--- a/third_party/blink/renderer/core/messaging/message_port.h
+++ b/third_party/blink/renderer/core/messaging/message_port.h
@@ -32,7 +32,7 @@
 #include "base/single_thread_task_runner.h"
 #include "mojo/public/cpp/bindings/connector.h"
 #include "mojo/public/cpp/bindings/message.h"
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
 #include "third_party/blink/public/platform/web_vector.h"
 #include "third_party/blink/renderer/bindings/core/v8/active_script_wrappable.h"
 #include "third_party/blink/renderer/bindings/core/v8/serialization/serialized_script_value.h"
diff --git a/third_party/blink/renderer/core/page/focus_changed_observer.cc b/third_party/blink/renderer/core/page/focus_changed_observer.cc
index 7e051af6..d4e9c9f 100644
--- a/third_party/blink/renderer/core/page/focus_changed_observer.cc
+++ b/third_party/blink/renderer/core/page/focus_changed_observer.cc
@@ -4,6 +4,7 @@
 
 #include "third_party/blink/renderer/core/page/focus_changed_observer.h"
 
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/page/focus_controller.h"
 #include "third_party/blink/renderer/core/page/page.h"
 
diff --git a/third_party/blink/renderer/core/page/page.cc b/third_party/blink/renderer/core/page/page.cc
index 7304719..6255950b 100644
--- a/third_party/blink/renderer/core/page/page.cc
+++ b/third_party/blink/renderer/core/page/page.cc
@@ -38,6 +38,7 @@
 #include "third_party/blink/renderer/core/frame/frame_console.h"
 #include "third_party/blink/renderer/core/frame/link_highlights.h"
 #include "third_party/blink/renderer/core/frame/local_dom_window.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_client.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/frame/page_scale_constraints.h"
@@ -277,6 +278,10 @@
   main_frame_ = main_frame;
 }
 
+LocalFrame* Page::DeprecatedLocalMainFrame() const {
+  return ToLocalFrame(main_frame_);
+}
+
 void Page::DocumentDetached(Document* document) {
   pointer_lock_controller_->DocumentDetached(document);
   context_menu_controller_->DocumentDetached(document);
diff --git a/third_party/blink/renderer/core/page/page.h b/third_party/blink/renderer/core/page/page.h
index 1d53858f..937a60f0 100644
--- a/third_party/blink/renderer/core/page/page.h
+++ b/third_party/blink/renderer/core/page/page.h
@@ -30,7 +30,6 @@
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/frame/deprecation.h"
 #include "third_party/blink/renderer/core/frame/hosts_using_features.h"
-#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/settings_delegate.h"
 #include "third_party/blink/renderer/core/page/page_animator.h"
 #include "third_party/blink/renderer/core/page/page_visibility_notifier.h"
@@ -58,6 +57,8 @@
 class FocusController;
 class Frame;
 class LinkHighlights;
+class LocalFrame;
+class LocalFrameView;
 class OverscrollController;
 class PageOverlay;
 struct PageScaleConstraints;
@@ -68,6 +69,7 @@
 class ScopedPagePauser;
 class ScrollingCoordinator;
 class ScrollbarTheme;
+class SecurityOrigin;
 class Settings;
 class ConsoleMessageStorage;
 class TopDocumentRootScrollerController;
@@ -150,9 +152,7 @@
   // depends on this will generally have to be rewritten to propagate any
   // necessary state through all renderer processes for that page and/or
   // coordinate/rely on the browser process to help dispatch/coordinate work.
-  LocalFrame* DeprecatedLocalMainFrame() const {
-    return ToLocalFrame(main_frame_);
-  }
+  LocalFrame* DeprecatedLocalMainFrame() const;
 
   void DocumentDetached(Document*);
 
diff --git a/third_party/blink/renderer/core/page/validation_message_client_impl.cc b/third_party/blink/renderer/core/page/validation_message_client_impl.cc
index 52b2a00e..c6623a5 100644
--- a/third_party/blink/renderer/core/page/validation_message_client_impl.cc
+++ b/third_party/blink/renderer/core/page/validation_message_client_impl.cc
@@ -32,6 +32,7 @@
 #include "third_party/blink/public/platform/task_type.h"
 #include "third_party/blink/public/web/web_text_direction.h"
 #include "third_party/blink/renderer/core/dom/element.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
 #include "third_party/blink/renderer/core/page/chrome_client.h"
 #include "third_party/blink/renderer/core/page/validation_message_overlay_delegate.h"
diff --git a/third_party/blink/renderer/core/paint/object_paint_invalidator.cc b/third_party/blink/renderer/core/paint/object_paint_invalidator.cc
index d1a31aa0..681cd12 100644
--- a/third_party/blink/renderer/core/paint/object_paint_invalidator.cc
+++ b/third_party/blink/renderer/core/paint/object_paint_invalidator.cc
@@ -171,6 +171,19 @@
   traverse(object_);
 }
 
+namespace {
+bool IsClientNGPaintFragmentForObject(const DisplayItemClient& client,
+                                      const LayoutObject& object) {
+  if (!RuntimeEnabledFeatures::LayoutNGEnabled())
+    return false;
+  // TODO(crbug.com/880519): This hack only makes current invalidation tracking
+  // layout tests pass with LayoutNG. More work is needed if we want to launch
+  // the invalidation tracking feature.
+  return object.IsLayoutBlockFlow() &&
+         &client == ToLayoutBlockFlow(object).PaintFragment();
+}
+}  // namespace
+
 void ObjectPaintInvalidator::InvalidateDisplayItemClient(
     const DisplayItemClient& client,
     PaintInvalidationReason reason) {
@@ -180,7 +193,8 @@
   // reduce the cost.
   DCHECK(!object_.PaintingLayer() || object_.PaintingLayer()->NeedsRepaint());
 
-  if (&client == &object_) {
+  if (&client == &object_ ||
+      IsClientNGPaintFragmentForObject(client, object_)) {
     TRACE_EVENT_INSTANT1(
         TRACE_DISABLED_BY_DEFAULT("devtools.timeline.invalidationTracking"),
         "PaintInvalidationTracking", TRACE_EVENT_SCOPE_THREAD, "data",
diff --git a/third_party/blink/renderer/core/style/computed_style.cc b/third_party/blink/renderer/core/style/computed_style.cc
index 8ca9358..bf54387cd 100644
--- a/third_party/blink/renderer/core/style/computed_style.cc
+++ b/third_party/blink/renderer/core/style/computed_style.cc
@@ -64,6 +64,7 @@
 #include "third_party/blink/renderer/platform/graphics/path.h"
 #include "third_party/blink/renderer/platform/length_functions.h"
 #include "third_party/blink/renderer/platform/text/capitalize.h"
+#include "third_party/blink/renderer/platform/text/character.h"
 #include "third_party/blink/renderer/platform/transforms/rotate_transform_operation.h"
 #include "third_party/blink/renderer/platform/transforms/scale_transform_operation.h"
 #include "third_party/blink/renderer/platform/transforms/translate_transform_operation.h"
@@ -918,7 +919,7 @@
   // which requires flattening. See ComputedStyle::UsedTransformStyle3D() and
   // ComputedStyle::HasGroupingProperty().
   // This is legacy behavior that is left ambiguous in the official specs.
-  // See crbug.com/663650 for more details."
+  // See https://crbug.com/663650 for more details."
   if (TransformStyle3D() == ETransformStyle3D::kPreserve3d) {
     SetIsStackingContext(true);
     return;
@@ -1417,6 +1418,34 @@
                                                         : !should_use;
 }
 
+// Unicode 11 introduced Georgian capital letters (U+1C90 - U+1CBA,
+// U+1CB[D-F]), but virtually no font covers them. For now map them back
+// to their lowercase counterparts (U+10D0 - U+10FA, U+10F[D-F]).
+// https://www.unicode.org/charts/PDF/U10A0.pdf
+// https://www.unicode.org/charts/PDF/U1C90.pdf
+// See https://crbug.com/865427 .
+// TODO(jshin): Make this platform-dependent. For instance, turn this
+// off when CrOS gets new Georgian fonts covering capital letters.
+// ( https://crbug.com/880144 ).
+static String DisableNewGeorgianCapitalLetters(const String& text) {
+  if (text.IsNull() || text.Is8Bit())
+    return text;
+  unsigned length = text.length();
+  const StringImpl& input = *(text.Impl());
+  StringBuilder result;
+  result.ReserveCapacity(length);
+  // |input| must be well-formed UTF-16 so that there's no worry
+  // about surrogate handling.
+  for (unsigned i = 0; i < length; ++i) {
+    UChar character = input[i];
+    if (Character::IsModernGeorgianUppercase(character))
+      result.Append(Character::LowercaseModernGeorgianUppercase(character));
+    else
+      result.Append(character);
+  }
+  return result.ToString();
+}
+
 void ComputedStyle::ApplyTextTransform(String* text,
                                        UChar previous_character) const {
   switch (TextTransform()) {
@@ -1426,7 +1455,7 @@
       *text = Capitalize(*text, previous_character);
       return;
     case ETextTransform::kUppercase:
-      *text = text->UpperUnicode(Locale());
+      *text = DisableNewGeorgianCapitalLetters(text->UpperUnicode(Locale()));
       return;
     case ETextTransform::kLowercase:
       *text = text->LowerUnicode(Locale());
diff --git a/third_party/blink/renderer/core/style/style_fetched_image.cc b/third_party/blink/renderer/core/style/style_fetched_image.cc
index 9e31e74..44f870d4 100644
--- a/third_party/blink/renderer/core/style/style_fetched_image.cc
+++ b/third_party/blink/renderer/core/style/style_fetched_image.cc
@@ -54,6 +54,15 @@
   image_ = nullptr;
 }
 
+bool StyleFetchedImage::IsEqual(const StyleImage& other) const {
+  if (!other.IsImageResource())
+    return false;
+  const auto& other_image = ToStyleFetchedImage(other);
+  if (image_ != other_image.image_)
+    return false;
+  return url_ == other_image.url_;
+}
+
 WrappedImagePtr StyleFetchedImage::Data() const {
   return image_.Get();
 }
diff --git a/third_party/blink/renderer/core/style/style_fetched_image.h b/third_party/blink/renderer/core/style/style_fetched_image.h
index b70e265..1e80f57 100644
--- a/third_party/blink/renderer/core/style/style_fetched_image.h
+++ b/third_party/blink/renderer/core/style/style_fetched_image.h
@@ -80,6 +80,7 @@
                     FetchParameters&,
                     bool is_lazyload_deferred);
 
+  bool IsEqual(const StyleImage&) const override;
   void Dispose();
 
   Member<ImageResourceContent> image_;
diff --git a/third_party/blink/renderer/core/style/style_fetched_image_set.cc b/third_party/blink/renderer/core/style/style_fetched_image_set.cc
index 86def132..c9649cdb 100644
--- a/third_party/blink/renderer/core/style/style_fetched_image_set.cc
+++ b/third_party/blink/renderer/core/style/style_fetched_image_set.cc
@@ -51,6 +51,15 @@
   best_fit_image_ = nullptr;
 }
 
+bool StyleFetchedImageSet::IsEqual(const StyleImage& other) const {
+  if (!other.IsImageResourceSet())
+    return false;
+  const auto& other_image = ToStyleFetchedImageSet(other);
+  if (best_fit_image_ != other_image.best_fit_image_)
+    return false;
+  return url_ == other_image.url_;
+}
+
 WrappedImagePtr StyleFetchedImageSet::Data() const {
   return best_fit_image_.Get();
 }
diff --git a/third_party/blink/renderer/core/style/style_fetched_image_set.h b/third_party/blink/renderer/core/style/style_fetched_image_set.h
index faab1fe..3872da1 100644
--- a/third_party/blink/renderer/core/style/style_fetched_image_set.h
+++ b/third_party/blink/renderer/core/style/style_fetched_image_set.h
@@ -88,6 +88,7 @@
                        CSSImageSetValue*,
                        const KURL&);
 
+  bool IsEqual(const StyleImage& other) const override;
   void Dispose();
 
   String DebugName() const override { return "StyleFetchedImageSet"; }
diff --git a/third_party/blink/renderer/core/style/style_generated_image.cc b/third_party/blink/renderer/core/style/style_generated_image.cc
index adaad59..a5e9f92 100644
--- a/third_party/blink/renderer/core/style/style_generated_image.cc
+++ b/third_party/blink/renderer/core/style/style_generated_image.cc
@@ -38,6 +38,13 @@
     is_paint_image_ = true;
 }
 
+bool StyleGeneratedImage::IsEqual(const StyleImage& other) const {
+  if (!other.IsGeneratedImage())
+    return false;
+  const auto& other_generated = ToStyleGeneratedImage(other);
+  return image_generator_value_ == other_generated.image_generator_value_;
+}
+
 CSSValue* StyleGeneratedImage::CssValue() const {
   return image_generator_value_.Get();
 }
diff --git a/third_party/blink/renderer/core/style/style_generated_image.h b/third_party/blink/renderer/core/style/style_generated_image.h
index b534813..c155958 100644
--- a/third_party/blink/renderer/core/style/style_generated_image.h
+++ b/third_party/blink/renderer/core/style/style_generated_image.h
@@ -66,6 +66,8 @@
  private:
   StyleGeneratedImage(const CSSImageGeneratorValue&);
 
+  bool IsEqual(const StyleImage&) const override;
+
   // TODO(sashab): Replace this with <const CSSImageGeneratorValue> once
   // Member<> supports const types.
   Member<CSSImageGeneratorValue> image_generator_value_;
diff --git a/third_party/blink/renderer/core/style/style_image.h b/third_party/blink/renderer/core/style/style_image.h
index 4f90fd4..95bcfa01 100644
--- a/third_party/blink/renderer/core/style/style_image.h
+++ b/third_party/blink/renderer/core/style/style_image.h
@@ -49,9 +49,7 @@
  public:
   virtual ~StyleImage() = default;
 
-  bool operator==(const StyleImage& other) const {
-    return Data() == other.Data();
-  }
+  bool operator==(const StyleImage& other) const { return IsEqual(other); }
 
   // Returns a CSSValue representing the origin <image> value. May not be the
   // actual CSSValue from which this StyleImage was originally created if the
@@ -163,6 +161,8 @@
   bool is_paint_image_ : 1;
   bool is_lazyload_possibly_deferred_ : 1;
 
+  virtual bool IsEqual(const StyleImage&) const = 0;
+
   FloatSize ApplyZoom(const FloatSize&, float multiplier) const;
   FloatSize ImageSizeForSVGImage(SVGImage*,
                                  float multiplier,
diff --git a/third_party/blink/renderer/core/style/style_pending_image.h b/third_party/blink/renderer/core/style/style_pending_image.h
index 5b41005..1ef61e4 100644
--- a/third_party/blink/renderer/core/style/style_pending_image.h
+++ b/third_party/blink/renderer/core/style/style_pending_image.h
@@ -103,6 +103,8 @@
     is_pending_image_ = true;
   }
 
+  bool IsEqual(const StyleImage& other) const override;
+
   // TODO(sashab): Replace this with <const CSSValue> once Member<>
   // supports const types.
   Member<CSSValue> value_;
@@ -110,5 +112,12 @@
 
 DEFINE_STYLE_IMAGE_TYPE_CASTS(StylePendingImage, IsPendingImage());
 
+inline bool StylePendingImage::IsEqual(const StyleImage& other) const {
+  if (!other.IsPendingImage())
+    return false;
+  const auto& other_pending = ToStylePendingImage(other);
+  return value_ == other_pending.value_;
+}
+
 }  // namespace blink
 #endif
diff --git a/third_party/blink/renderer/core/svg/svg_animated_enumeration.h b/third_party/blink/renderer/core/svg/svg_animated_enumeration.h
index 34d845a..b64f188 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_enumeration.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_enumeration.h
@@ -44,15 +44,17 @@
       Enum initial_value) {
     return new SVGAnimatedEnumeration(
         context_element, attribute_name,
-        SVGEnumeration<Enum>::Create(initial_value));
+        SVGEnumeration<Enum>::Create(initial_value),
+        static_cast<unsigned>(initial_value));
   }
 
   static SVGAnimatedEnumeration<Enum>* Create(
       SVGElement* context_element,
       const QualifiedName& attribute_name,
       SVGEnumeration<Enum>* initial_value) {
-    return new SVGAnimatedEnumeration(context_element, attribute_name,
-                                      initial_value);
+    return new SVGAnimatedEnumeration(
+        context_element, attribute_name, initial_value,
+        static_cast<unsigned>(initial_value->EnumValue()));
   }
 
   SVGEnumeration<Enum>* BaseValue() {
@@ -73,10 +75,12 @@
  protected:
   SVGAnimatedEnumeration(SVGElement* context_element,
                          const QualifiedName& attribute_name,
-                         SVGEnumeration<Enum>* initial_value)
+                         SVGEnumeration<Enum>* initial_value,
+                         unsigned initial_enum_value)
       : SVGAnimatedEnumerationBase(context_element,
                                    attribute_name,
-                                   initial_value) {}
+                                   initial_value,
+                                   initial_enum_value) {}
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/svg/svg_animated_enumeration_base.h b/third_party/blink/renderer/core/svg/svg_animated_enumeration_base.h
index 0ada0b5..d101766a 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_enumeration_base.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_enumeration_base.h
@@ -56,10 +56,13 @@
  protected:
   SVGAnimatedEnumerationBase(SVGElement* context_element,
                              const QualifiedName& attribute_name,
-                             SVGEnumerationBase* initial_value)
+                             SVGEnumerationBase* initial_value,
+                             unsigned initial_enum_value)
       : SVGAnimatedProperty<SVGEnumerationBase>(context_element,
                                                 attribute_name,
-                                                initial_value) {}
+                                                initial_value,
+                                                CSSPropertyInvalid,
+                                                initial_enum_value) {}
 };
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/svg/svg_animated_number.h b/third_party/blink/renderer/core/svg/svg_animated_number.h
index 074c747..cbf8d4b 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_number.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_number.h
@@ -49,6 +49,13 @@
  public:
   static SVGAnimatedNumber* Create(SVGElement* context_element,
                                    const QualifiedName& attribute_name,
+                                   float initial_number) {
+    SVGNumber* initial_value = SVGNumber::Create(initial_number);
+    return new SVGAnimatedNumber(context_element, attribute_name,
+                                 initial_value);
+  }
+  static SVGAnimatedNumber* Create(SVGElement* context_element,
+                                   const QualifiedName& attribute_name,
                                    SVGNumber* initial_value) {
     return new SVGAnimatedNumber(context_element, attribute_name,
                                  initial_value);
@@ -67,9 +74,12 @@
   SVGAnimatedNumber(SVGElement* context_element,
                     const QualifiedName& attribute_name,
                     SVGNumber* initial_value)
-      : SVGAnimatedProperty<SVGNumber>(context_element,
-                                       attribute_name,
-                                       initial_value),
+      : SVGAnimatedProperty<SVGNumber>(
+            context_element,
+            attribute_name,
+            initial_value,
+            CSSPropertyInvalid,
+            static_cast<unsigned>(initial_value->Value())),
         parent_number_optional_number_(nullptr) {}
 
   Member<SVGAnimatedNumberOptionalNumber> parent_number_optional_number_;
diff --git a/third_party/blink/renderer/core/svg/svg_animated_number_optional_number.cc b/third_party/blink/renderer/core/svg/svg_animated_number_optional_number.cc
index 86d0c73a..8b76f16 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_number_optional_number.cc
+++ b/third_party/blink/renderer/core/svg/svg_animated_number_optional_number.cc
@@ -24,14 +24,14 @@
 SVGAnimatedNumberOptionalNumber::SVGAnimatedNumberOptionalNumber(
     SVGElement* context_element,
     const QualifiedName& attribute_name,
-    float initial_first_value,
-    float initial_second_value)
+    float initial_value)
     : SVGAnimatedPropertyCommon<SVGNumberOptionalNumber>(
           context_element,
           attribute_name,
-          SVGNumberOptionalNumber::Create(
-              SVGNumber::Create(initial_first_value),
-              SVGNumber::Create(initial_second_value))),
+          SVGNumberOptionalNumber::Create(SVGNumber::Create(initial_value),
+                                          SVGNumber::Create(initial_value)),
+          CSSPropertyInvalid,
+          static_cast<unsigned>(initial_value)),
       first_number_(SVGAnimatedNumber::Create(context_element,
                                               attribute_name,
                                               BaseValue()->FirstNumber())),
diff --git a/third_party/blink/renderer/core/svg/svg_animated_number_optional_number.h b/third_party/blink/renderer/core/svg/svg_animated_number_optional_number.h
index a8170da..658b146 100644
--- a/third_party/blink/renderer/core/svg/svg_animated_number_optional_number.h
+++ b/third_party/blink/renderer/core/svg/svg_animated_number_optional_number.h
@@ -52,11 +52,9 @@
   static SVGAnimatedNumberOptionalNumber* Create(
       SVGElement* context_element,
       const QualifiedName& attribute_name,
-      float initial_first_value = 0,
-      float initial_second_value = 0) {
+      float initial_value) {
     return new SVGAnimatedNumberOptionalNumber(context_element, attribute_name,
-                                               initial_first_value,
-                                               initial_second_value);
+                                               initial_value);
   }
 
   void SetAnimatedValue(SVGPropertyBase*) override;
@@ -71,8 +69,7 @@
  protected:
   SVGAnimatedNumberOptionalNumber(SVGElement* context_element,
                                   const QualifiedName& attribute_name,
-                                  float initial_first_value,
-                                  float initial_second_value);
+                                  float initial_value);
 
   Member<SVGAnimatedNumber> first_number_;
   Member<SVGAnimatedNumber> second_number_;
diff --git a/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.cc b/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.cc
index 1052202..2781cab 100644
--- a/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_component_transfer_function_element.cc
@@ -50,21 +50,12 @@
     : SVGElement(tag_name, document),
       table_values_(
           SVGAnimatedNumberList::Create(this, SVGNames::tableValuesAttr)),
-      slope_(SVGAnimatedNumber::Create(this,
-                                       SVGNames::slopeAttr,
-                                       SVGNumber::Create(1))),
-      intercept_(SVGAnimatedNumber::Create(this,
-                                           SVGNames::interceptAttr,
-                                           SVGNumber::Create())),
-      amplitude_(SVGAnimatedNumber::Create(this,
-                                           SVGNames::amplitudeAttr,
-                                           SVGNumber::Create(1))),
-      exponent_(SVGAnimatedNumber::Create(this,
-                                          SVGNames::exponentAttr,
-                                          SVGNumber::Create(1))),
-      offset_(SVGAnimatedNumber::Create(this,
-                                        SVGNames::offsetAttr,
-                                        SVGNumber::Create())),
+      slope_(SVGAnimatedNumber::Create(this, SVGNames::slopeAttr, 1)),
+      intercept_(
+          SVGAnimatedNumber::Create(this, SVGNames::interceptAttr, 0.0f)),
+      amplitude_(SVGAnimatedNumber::Create(this, SVGNames::amplitudeAttr, 1)),
+      exponent_(SVGAnimatedNumber::Create(this, SVGNames::exponentAttr, 1)),
+      offset_(SVGAnimatedNumber::Create(this, SVGNames::offsetAttr, 0.0f)),
       type_(SVGAnimatedEnumeration<ComponentTransferType>::Create(
           this,
           SVGNames::typeAttr,
diff --git a/third_party/blink/renderer/core/svg/svg_enumeration.h b/third_party/blink/renderer/core/svg/svg_enumeration.h
index db15a85..4b4a074 100644
--- a/third_party/blink/renderer/core/svg/svg_enumeration.h
+++ b/third_party/blink/renderer/core/svg/svg_enumeration.h
@@ -80,6 +80,11 @@
   // relevant interface.
   unsigned short MaxExposedEnumValue() const { return max_exposed_; }
 
+  void SetInitial(unsigned value) {
+    SetValue(static_cast<unsigned short>(value));
+  }
+  static constexpr int kInitialValueBits = 3;
+
  protected:
   SVGEnumerationBase(unsigned short value,
                      const StringEntries& entries,
diff --git a/third_party/blink/renderer/core/svg/svg_fe_composite_element.cc b/third_party/blink/renderer/core/svg/svg_fe_composite_element.cc
index 1278b7b8..a86fdd0e 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_composite_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_composite_element.cc
@@ -49,18 +49,10 @@
 
 inline SVGFECompositeElement::SVGFECompositeElement(Document& document)
     : SVGFilterPrimitiveStandardAttributes(SVGNames::feCompositeTag, document),
-      k1_(SVGAnimatedNumber::Create(this,
-                                    SVGNames::k1Attr,
-                                    SVGNumber::Create())),
-      k2_(SVGAnimatedNumber::Create(this,
-                                    SVGNames::k2Attr,
-                                    SVGNumber::Create())),
-      k3_(SVGAnimatedNumber::Create(this,
-                                    SVGNames::k3Attr,
-                                    SVGNumber::Create())),
-      k4_(SVGAnimatedNumber::Create(this,
-                                    SVGNames::k4Attr,
-                                    SVGNumber::Create())),
+      k1_(SVGAnimatedNumber::Create(this, SVGNames::k1Attr, 0.0f)),
+      k2_(SVGAnimatedNumber::Create(this, SVGNames::k2Attr, 0.0f)),
+      k3_(SVGAnimatedNumber::Create(this, SVGNames::k3Attr, 0.0f)),
+      k4_(SVGAnimatedNumber::Create(this, SVGNames::k4Attr, 0.0f)),
       in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)),
       in2_(SVGAnimatedString::Create(this, SVGNames::in2Attr)),
       svg_operator_(SVGAnimatedEnumeration<CompositeOperationType>::Create(
diff --git a/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.cc b/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.cc
index 0536c88..f9634c7 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.cc
@@ -78,12 +78,8 @@
     Document& document)
     : SVGFilterPrimitiveStandardAttributes(SVGNames::feConvolveMatrixTag,
                                            document),
-      bias_(SVGAnimatedNumber::Create(this,
-                                      SVGNames::biasAttr,
-                                      SVGNumber::Create())),
-      divisor_(SVGAnimatedNumber::Create(this,
-                                         SVGNames::divisorAttr,
-                                         SVGNumber::Create())),
+      bias_(SVGAnimatedNumber::Create(this, SVGNames::biasAttr, 0.0f)),
+      divisor_(SVGAnimatedNumber::Create(this, SVGNames::divisorAttr, 1)),
       in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)),
       edge_mode_(
           SVGAnimatedEnumeration<EdgeModeType>::Create(this,
@@ -93,7 +89,8 @@
           SVGAnimatedNumberList::Create(this, SVGNames::kernelMatrixAttr)),
       kernel_unit_length_(SVGAnimatedNumberOptionalNumber::Create(
           this,
-          SVGNames::kernelUnitLengthAttr)),
+          SVGNames::kernelUnitLengthAttr,
+          0.0f)),
       order_(SVGAnimatedOrder::Create(this)),
       preserve_alpha_(
           SVGAnimatedBoolean::Create(this, SVGNames::preserveAlphaAttr)),
@@ -151,6 +148,17 @@
   return target;
 }
 
+float SVGFEConvolveMatrixElement::ComputeDivisor() const {
+  if (divisor_->IsSpecified())
+    return divisor_->CurrentValue()->Value();
+  float divisor_value = 0;
+  SVGNumberList* kernel_matrix = kernel_matrix_->CurrentValue();
+  size_t kernel_matrix_size = kernel_matrix->length();
+  for (size_t i = 0; i < kernel_matrix_size; ++i)
+    divisor_value += kernel_matrix->at(i)->Value();
+  return divisor_value ? divisor_value : 1;
+}
+
 bool SVGFEConvolveMatrixElement::SetFilterEffectAttribute(
     FilterEffect* effect,
     const QualifiedName& attr_name) {
@@ -159,7 +167,7 @@
     return convolve_matrix->SetEdgeMode(
         edge_mode_->CurrentValue()->EnumValue());
   if (attr_name == SVGNames::divisorAttr)
-    return convolve_matrix->SetDivisor(divisor_->CurrentValue()->Value());
+    return convolve_matrix->SetDivisor(ComputeDivisor());
   if (attr_name == SVGNames::biasAttr)
     return convolve_matrix->SetBias(bias_->CurrentValue()->Value());
   if (attr_name == SVGNames::targetXAttr || attr_name == SVGNames::targetYAttr)
@@ -200,18 +208,8 @@
       AtomicString(in1_->CurrentValue()->Value()));
   DCHECK(input1);
 
-  float divisor_value = divisor_->CurrentValue()->Value();
-  if (!divisor_->IsSpecified()) {
-    SVGNumberList* kernel_matrix = kernel_matrix_->CurrentValue();
-    size_t kernel_matrix_size = kernel_matrix->length();
-    for (size_t i = 0; i < kernel_matrix_size; ++i)
-      divisor_value += kernel_matrix->at(i)->Value();
-    if (!divisor_value)
-      divisor_value = 1;
-  }
-
   FilterEffect* effect = FEConvolveMatrix::Create(
-      filter, MatrixOrder(), divisor_value, bias_->CurrentValue()->Value(),
+      filter, MatrixOrder(), ComputeDivisor(), bias_->CurrentValue()->Value(),
       TargetPoint(), edge_mode_->CurrentValue()->EnumValue(),
       preserve_alpha_->CurrentValue()->Value(),
       kernel_matrix_->CurrentValue()->ToFloatVector());
diff --git a/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.h b/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.h
index 2160f92..d870327 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.h
+++ b/third_party/blink/renderer/core/svg/svg_fe_convolve_matrix_element.h
@@ -67,6 +67,7 @@
 
   IntSize MatrixOrder() const;
   IntPoint TargetPoint() const;
+  float ComputeDivisor() const;
 
   bool SetFilterEffectAttribute(FilterEffect*, const QualifiedName&) override;
   void SvgAttributeChanged(const QualifiedName&) override;
diff --git a/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.cc b/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.cc
index 53b5eae..7aa058f 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_diffuse_lighting_element.cc
@@ -31,15 +31,14 @@
     Document& document)
     : SVGFilterPrimitiveStandardAttributes(SVGNames::feDiffuseLightingTag,
                                            document),
-      diffuse_constant_(SVGAnimatedNumber::Create(this,
-                                                  SVGNames::diffuseConstantAttr,
-                                                  SVGNumber::Create(1))),
-      surface_scale_(SVGAnimatedNumber::Create(this,
-                                               SVGNames::surfaceScaleAttr,
-                                               SVGNumber::Create(1))),
+      diffuse_constant_(
+          SVGAnimatedNumber::Create(this, SVGNames::diffuseConstantAttr, 1)),
+      surface_scale_(
+          SVGAnimatedNumber::Create(this, SVGNames::surfaceScaleAttr, 1)),
       kernel_unit_length_(SVGAnimatedNumberOptionalNumber::Create(
           this,
-          SVGNames::kernelUnitLengthAttr)),
+          SVGNames::kernelUnitLengthAttr,
+          0.0f)),
       in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)) {
   AddToPropertyMap(diffuse_constant_);
   AddToPropertyMap(surface_scale_);
diff --git a/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.cc b/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.cc
index a9eb215..653f37e20 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_displacement_map_element.cc
@@ -41,9 +41,7 @@
     Document& document)
     : SVGFilterPrimitiveStandardAttributes(SVGNames::feDisplacementMapTag,
                                            document),
-      scale_(SVGAnimatedNumber::Create(this,
-                                       SVGNames::scaleAttr,
-                                       SVGNumber::Create(0))),
+      scale_(SVGAnimatedNumber::Create(this, SVGNames::scaleAttr, 0.0f)),
       in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)),
       in2_(SVGAnimatedString::Create(this, SVGNames::in2Attr)),
       x_channel_selector_(SVGAnimatedEnumeration<ChannelSelectorType>::Create(
diff --git a/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.cc b/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.cc
index cc7cccdc..dcdce53 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_drop_shadow_element.cc
@@ -30,16 +30,11 @@
 
 inline SVGFEDropShadowElement::SVGFEDropShadowElement(Document& document)
     : SVGFilterPrimitiveStandardAttributes(SVGNames::feDropShadowTag, document),
-      dx_(SVGAnimatedNumber::Create(this,
-                                    SVGNames::dxAttr,
-                                    SVGNumber::Create(2))),
-      dy_(SVGAnimatedNumber::Create(this,
-                                    SVGNames::dyAttr,
-                                    SVGNumber::Create(2))),
+      dx_(SVGAnimatedNumber::Create(this, SVGNames::dxAttr, 2)),
+      dy_(SVGAnimatedNumber::Create(this, SVGNames::dyAttr, 2)),
       std_deviation_(
           SVGAnimatedNumberOptionalNumber::Create(this,
                                                   SVGNames::stdDeviationAttr,
-                                                  2,
                                                   2)),
       in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)) {
   AddToPropertyMap(dx_);
diff --git a/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.cc b/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.cc
index fb1da2c..2c234c1 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_gaussian_blur_element.cc
@@ -32,8 +32,7 @@
       std_deviation_(
           SVGAnimatedNumberOptionalNumber::Create(this,
                                                   SVGNames::stdDeviationAttr,
-                                                  0,
-                                                  0)),
+                                                  0.0f)),
       in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)) {
   AddToPropertyMap(std_deviation_);
   AddToPropertyMap(in1_);
diff --git a/third_party/blink/renderer/core/svg/svg_fe_light_element.cc b/third_party/blink/renderer/core/svg/svg_fe_light_element.cc
index 1124497..fc0d2d72 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_light_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_light_element.cc
@@ -32,32 +32,24 @@
 SVGFELightElement::SVGFELightElement(const QualifiedName& tag_name,
                                      Document& document)
     : SVGElement(tag_name, document),
-      azimuth_(SVGAnimatedNumber::Create(this,
-                                         SVGNames::azimuthAttr,
-                                         SVGNumber::Create())),
-      elevation_(SVGAnimatedNumber::Create(this,
-                                           SVGNames::elevationAttr,
-                                           SVGNumber::Create())),
-      x_(SVGAnimatedNumber::Create(this, SVGNames::xAttr, SVGNumber::Create())),
-      y_(SVGAnimatedNumber::Create(this, SVGNames::yAttr, SVGNumber::Create())),
-      z_(SVGAnimatedNumber::Create(this, SVGNames::zAttr, SVGNumber::Create())),
-      points_at_x_(SVGAnimatedNumber::Create(this,
-                                             SVGNames::pointsAtXAttr,
-                                             SVGNumber::Create())),
-      points_at_y_(SVGAnimatedNumber::Create(this,
-                                             SVGNames::pointsAtYAttr,
-                                             SVGNumber::Create())),
-      points_at_z_(SVGAnimatedNumber::Create(this,
-                                             SVGNames::pointsAtZAttr,
-                                             SVGNumber::Create())),
+      azimuth_(SVGAnimatedNumber::Create(this, SVGNames::azimuthAttr, 0.0f)),
+      elevation_(
+          SVGAnimatedNumber::Create(this, SVGNames::elevationAttr, 0.0f)),
+      x_(SVGAnimatedNumber::Create(this, SVGNames::xAttr, 0.0f)),
+      y_(SVGAnimatedNumber::Create(this, SVGNames::yAttr, 0.0f)),
+      z_(SVGAnimatedNumber::Create(this, SVGNames::zAttr, 0.0f)),
+      points_at_x_(
+          SVGAnimatedNumber::Create(this, SVGNames::pointsAtXAttr, 0.0f)),
+      points_at_y_(
+          SVGAnimatedNumber::Create(this, SVGNames::pointsAtYAttr, 0.0f)),
+      points_at_z_(
+          SVGAnimatedNumber::Create(this, SVGNames::pointsAtZAttr, 0.0f)),
       specular_exponent_(
-          SVGAnimatedNumber::Create(this,
-                                    SVGNames::specularExponentAttr,
-                                    SVGNumber::Create(1))),
+          SVGAnimatedNumber::Create(this, SVGNames::specularExponentAttr, 1)),
       limiting_cone_angle_(
           SVGAnimatedNumber::Create(this,
                                     SVGNames::limitingConeAngleAttr,
-                                    SVGNumber::Create())) {
+                                    0.0f)) {
   AddToPropertyMap(azimuth_);
   AddToPropertyMap(elevation_);
   AddToPropertyMap(x_);
diff --git a/third_party/blink/renderer/core/svg/svg_fe_morphology_element.cc b/third_party/blink/renderer/core/svg/svg_fe_morphology_element.cc
index 97be8bd..f673929 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_morphology_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_morphology_element.cc
@@ -37,8 +37,9 @@
 
 inline SVGFEMorphologyElement::SVGFEMorphologyElement(Document& document)
     : SVGFilterPrimitiveStandardAttributes(SVGNames::feMorphologyTag, document),
-      radius_(
-          SVGAnimatedNumberOptionalNumber::Create(this, SVGNames::radiusAttr)),
+      radius_(SVGAnimatedNumberOptionalNumber::Create(this,
+                                                      SVGNames::radiusAttr,
+                                                      0.0f)),
       in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)),
       svg_operator_(SVGAnimatedEnumeration<MorphologyOperatorType>::Create(
           this,
diff --git a/third_party/blink/renderer/core/svg/svg_fe_offset_element.cc b/third_party/blink/renderer/core/svg/svg_fe_offset_element.cc
index b1ab115a..05dd198 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_offset_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_offset_element.cc
@@ -28,12 +28,8 @@
 
 inline SVGFEOffsetElement::SVGFEOffsetElement(Document& document)
     : SVGFilterPrimitiveStandardAttributes(SVGNames::feOffsetTag, document),
-      dx_(SVGAnimatedNumber::Create(this,
-                                    SVGNames::dxAttr,
-                                    SVGNumber::Create())),
-      dy_(SVGAnimatedNumber::Create(this,
-                                    SVGNames::dyAttr,
-                                    SVGNumber::Create())),
+      dx_(SVGAnimatedNumber::Create(this, SVGNames::dxAttr, 0.0f)),
+      dy_(SVGAnimatedNumber::Create(this, SVGNames::dyAttr, 0.0f)),
       in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)) {
   AddToPropertyMap(dx_);
   AddToPropertyMap(dy_);
diff --git a/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.cc b/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.cc
index 88f88f9..a65591a 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_specular_lighting_element.cc
@@ -34,19 +34,15 @@
     : SVGFilterPrimitiveStandardAttributes(SVGNames::feSpecularLightingTag,
                                            document),
       specular_constant_(
-          SVGAnimatedNumber::Create(this,
-                                    SVGNames::specularConstantAttr,
-                                    SVGNumber::Create(1))),
+          SVGAnimatedNumber::Create(this, SVGNames::specularConstantAttr, 1)),
       specular_exponent_(
-          SVGAnimatedNumber::Create(this,
-                                    SVGNames::specularExponentAttr,
-                                    SVGNumber::Create(1))),
-      surface_scale_(SVGAnimatedNumber::Create(this,
-                                               SVGNames::surfaceScaleAttr,
-                                               SVGNumber::Create(1))),
+          SVGAnimatedNumber::Create(this, SVGNames::specularExponentAttr, 1)),
+      surface_scale_(
+          SVGAnimatedNumber::Create(this, SVGNames::surfaceScaleAttr, 1)),
       kernel_unit_length_(SVGAnimatedNumberOptionalNumber::Create(
           this,
-          SVGNames::kernelUnitLengthAttr)),
+          SVGNames::kernelUnitLengthAttr,
+          0.0f)),
       in1_(SVGAnimatedString::Create(this, SVGNames::inAttr)) {
   AddToPropertyMap(specular_constant_);
   AddToPropertyMap(specular_exponent_);
diff --git a/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.cc b/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.cc
index 9876abb0c..2a5626c2 100644
--- a/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.cc
+++ b/third_party/blink/renderer/core/svg/svg_fe_turbulence_element.cc
@@ -50,10 +50,9 @@
     : SVGFilterPrimitiveStandardAttributes(SVGNames::feTurbulenceTag, document),
       base_frequency_(
           SVGAnimatedNumberOptionalNumber::Create(this,
-                                                  SVGNames::baseFrequencyAttr)),
-      seed_(SVGAnimatedNumber::Create(this,
-                                      SVGNames::seedAttr,
-                                      SVGNumber::Create(0))),
+                                                  SVGNames::baseFrequencyAttr,
+                                                  0.0f)),
+      seed_(SVGAnimatedNumber::Create(this, SVGNames::seedAttr, 0.0f)),
       stitch_tiles_(SVGAnimatedEnumeration<SVGStitchOptions>::Create(
           this,
           SVGNames::stitchTilesAttr,
diff --git a/third_party/blink/renderer/core/svg/svg_number.h b/third_party/blink/renderer/core/svg/svg_number.h
index 4d0ab8e..7cb5255a 100644
--- a/third_party/blink/renderer/core/svg/svg_number.h
+++ b/third_party/blink/renderer/core/svg/svg_number.h
@@ -67,6 +67,9 @@
 
   static AnimatedPropertyType ClassType() { return kAnimatedNumber; }
 
+  void SetInitial(unsigned value) { SetValue(value); }
+  static constexpr int kInitialValueBits = 2;
+
  protected:
   explicit SVGNumber(float);
 
diff --git a/third_party/blink/renderer/core/svg/svg_number_optional_number.cc b/third_party/blink/renderer/core/svg/svg_number_optional_number.cc
index 4c368a1..ffbf1028c 100644
--- a/third_party/blink/renderer/core/svg/svg_number_optional_number.cc
+++ b/third_party/blink/renderer/core/svg/svg_number_optional_number.cc
@@ -83,6 +83,12 @@
   return parse_status;
 }
 
+void SVGNumberOptionalNumber::SetInitial(unsigned value) {
+  // Propagate the value to the split representation.
+  first_number_->SetInitial(value);
+  second_number_->SetInitial(value);
+}
+
 void SVGNumberOptionalNumber::Add(SVGPropertyBase* other, SVGElement*) {
   SVGNumberOptionalNumber* other_number_optional_number =
       ToSVGNumberOptionalNumber(other);
diff --git a/third_party/blink/renderer/core/svg/svg_number_optional_number.h b/third_party/blink/renderer/core/svg/svg_number_optional_number.h
index d41ba8d..07f8e51 100644
--- a/third_party/blink/renderer/core/svg/svg_number_optional_number.h
+++ b/third_party/blink/renderer/core/svg/svg_number_optional_number.h
@@ -53,6 +53,8 @@
 
   String ValueAsString() const override;
   SVGParsingError SetValueAsString(const String&);
+  void SetInitial(unsigned);
+  static constexpr int kInitialValueBits = SVGNumber::kInitialValueBits;
 
   void Add(SVGPropertyBase*, SVGElement*) override;
   void CalculateAnimatedValue(SVGAnimationElement*,
diff --git a/third_party/blink/renderer/core/svg/svg_static_string_list.cc b/third_party/blink/renderer/core/svg/svg_static_string_list.cc
index 8e65930..28b2e4a 100644
--- a/third_party/blink/renderer/core/svg/svg_static_string_list.cc
+++ b/third_party/blink/renderer/core/svg/svg_static_string_list.cc
@@ -35,11 +35,12 @@
 namespace blink {
 
 SVGStaticStringList::SVGStaticStringList(SVGElement* context_element,
-                                         const QualifiedName& attribute_name)
+                                         const QualifiedName& attribute_name,
+                                         SVGStringListBase* initial_value)
     : SVGAnimatedPropertyBase(kAnimatedUnknown,
                               context_element,
                               attribute_name),
-      value_(SVGStringList::Create()) {
+      value_(initial_value) {
   DCHECK(context_element);
 }
 
diff --git a/third_party/blink/renderer/core/svg/svg_static_string_list.h b/third_party/blink/renderer/core/svg/svg_static_string_list.h
index e5d13ab..1b3867c 100644
--- a/third_party/blink/renderer/core/svg/svg_static_string_list.h
+++ b/third_party/blink/renderer/core/svg/svg_static_string_list.h
@@ -48,9 +48,11 @@
   USING_GARBAGE_COLLECTED_MIXIN(SVGStaticStringList);
 
  public:
+  template <char list_delimiter>
   static SVGStaticStringList* Create(SVGElement* context_element,
                                      const QualifiedName& attribute_name) {
-    return new SVGStaticStringList(context_element, attribute_name);
+    return new SVGStaticStringList(context_element, attribute_name,
+                                   SVGStringList<list_delimiter>::Create());
   }
 
   ~SVGStaticStringList() override;
@@ -65,15 +67,17 @@
 
   SVGParsingError AttributeChanged(const String&) override;
 
-  SVGStringList* Value() { return value_.Get(); }
+  SVGStringListBase* Value() { return value_.Get(); }
   SVGStringListTearOff* TearOff();
 
   void Trace(blink::Visitor*) override;
 
  private:
-  SVGStaticStringList(SVGElement*, const QualifiedName&);
+  SVGStaticStringList(SVGElement*,
+                      const QualifiedName&,
+                      SVGStringListBase* initial_value);
 
-  Member<SVGStringList> value_;
+  Member<SVGStringListBase> value_;
   Member<SVGStringListTearOff> tear_off_;
 };
 
diff --git a/third_party/blink/renderer/core/svg/svg_string_list.cc b/third_party/blink/renderer/core/svg/svg_string_list.cc
index e3e1c5ac..96f5921 100644
--- a/third_party/blink/renderer/core/svg/svg_string_list.cc
+++ b/third_party/blink/renderer/core/svg/svg_string_list.cc
@@ -27,23 +27,22 @@
 
 namespace blink {
 
-SVGStringList::SVGStringList() = default;
+SVGStringListBase::~SVGStringListBase() = default;
 
-SVGStringList::~SVGStringList() = default;
-
-void SVGStringList::Initialize(const String& item) {
+void SVGStringListBase::Initialize(const String& item) {
   values_.clear();
   values_.push_back(item);
 }
 
-String SVGStringList::GetItem(size_t index, ExceptionState& exception_state) {
+String SVGStringListBase::GetItem(size_t index,
+                                  ExceptionState& exception_state) {
   if (!CheckIndexBound(index, exception_state))
     return String();
 
   return values_.at(index);
 }
 
-void SVGStringList::InsertItemBefore(const String& new_item, size_t index) {
+void SVGStringListBase::InsertItemBefore(const String& new_item, size_t index) {
   // Spec: If the index is greater than or equal to numberOfItems, then the new
   // item is appended to the end of the list.
   if (index > values_.size())
@@ -56,8 +55,8 @@
   values_.insert(index, new_item);
 }
 
-String SVGStringList::RemoveItem(size_t index,
-                                 ExceptionState& exception_state) {
+String SVGStringListBase::RemoveItem(size_t index,
+                                     ExceptionState& exception_state) {
   if (!CheckIndexBound(index, exception_state))
     return String();
 
@@ -66,13 +65,13 @@
   return old_item;
 }
 
-void SVGStringList::AppendItem(const String& new_item) {
+void SVGStringListBase::AppendItem(const String& new_item) {
   values_.push_back(new_item);
 }
 
-void SVGStringList::ReplaceItem(const String& new_item,
-                                size_t index,
-                                ExceptionState& exception_state) {
+void SVGStringListBase::ReplaceItem(const String& new_item,
+                                    size_t index,
+                                    ExceptionState& exception_state) {
   if (!CheckIndexBound(index, exception_state))
     return;
 
@@ -81,21 +80,23 @@
 }
 
 template <typename CharType>
-void SVGStringList::ParseInternal(const CharType*& ptr, const CharType* end) {
-  const UChar kDelimiter = ' ';
-
+void SVGStringListBase::ParseInternal(const CharType*& ptr,
+                                      const CharType* end,
+                                      char list_delimiter) {
   while (ptr < end) {
     const CharType* start = ptr;
-    while (ptr < end && *ptr != kDelimiter && !IsHTMLSpace<CharType>(*ptr))
+    while (ptr < end && *ptr != list_delimiter && !IsHTMLSpace<CharType>(*ptr))
       ptr++;
     if (ptr == start)
       break;
     values_.push_back(String(start, ptr - start));
-    SkipOptionalSVGSpacesOrDelimiter(ptr, end, kDelimiter);
+    SkipOptionalSVGSpacesOrDelimiter(ptr, end, list_delimiter);
   }
 }
 
-SVGParsingError SVGStringList::SetValueAsString(const String& data) {
+SVGParsingError SVGStringListBase::SetValueAsStringWithDelimiter(
+    const String& data,
+    char list_delimiter) {
   // FIXME: Add more error checking and reporting.
   values_.clear();
 
@@ -105,16 +106,17 @@
   if (data.Is8Bit()) {
     const LChar* ptr = data.Characters8();
     const LChar* end = ptr + data.length();
-    ParseInternal(ptr, end);
+    ParseInternal(ptr, end, list_delimiter);
   } else {
     const UChar* ptr = data.Characters16();
     const UChar* end = ptr + data.length();
-    ParseInternal(ptr, end);
+    ParseInternal(ptr, end, list_delimiter);
   }
   return SVGParseStatus::kNoError;
 }
 
-String SVGStringList::ValueAsString() const {
+String SVGStringListBase::ValueAsStringWithDelimiter(
+    char list_delimiter) const {
   if (values_.IsEmpty())
     return String();
 
@@ -127,7 +129,7 @@
     ++it;
 
     for (; it != it_end; ++it) {
-      builder.Append(' ');
+      builder.Append(list_delimiter);
       builder.Append(*it);
     }
   }
@@ -135,8 +137,8 @@
   return builder.ToString();
 }
 
-bool SVGStringList::CheckIndexBound(size_t index,
-                                    ExceptionState& exception_state) {
+bool SVGStringListBase::CheckIndexBound(size_t index,
+                                        ExceptionState& exception_state) {
   if (index >= values_.size()) {
     exception_state.ThrowDOMException(
         DOMExceptionCode::kIndexSizeError,
@@ -148,26 +150,26 @@
   return true;
 }
 
-void SVGStringList::Add(SVGPropertyBase* other, SVGElement* context_element) {
+void SVGStringListBase::Add(SVGPropertyBase* other,
+                            SVGElement* context_element) {
   // SVGStringList is never animated.
   NOTREACHED();
 }
 
-void SVGStringList::CalculateAnimatedValue(SVGAnimationElement*,
-                                           float,
-                                           unsigned,
-                                           SVGPropertyBase*,
-                                           SVGPropertyBase*,
-                                           SVGPropertyBase*,
-                                           SVGElement*) {
+void SVGStringListBase::CalculateAnimatedValue(SVGAnimationElement*,
+                                               float,
+                                               unsigned,
+                                               SVGPropertyBase*,
+                                               SVGPropertyBase*,
+                                               SVGPropertyBase*,
+                                               SVGElement*) {
   // SVGStringList is never animated.
   NOTREACHED();
 }
 
-float SVGStringList::CalculateDistance(SVGPropertyBase*, SVGElement*) {
+float SVGStringListBase::CalculateDistance(SVGPropertyBase*, SVGElement*) {
   // SVGStringList is never animated.
   NOTREACHED();
-
   return -1.0f;
 }
 
diff --git a/third_party/blink/renderer/core/svg/svg_string_list.h b/third_party/blink/renderer/core/svg/svg_string_list.h
index eee0d7f..875459f 100644
--- a/third_party/blink/renderer/core/svg/svg_string_list.h
+++ b/third_party/blink/renderer/core/svg/svg_string_list.h
@@ -54,13 +54,11 @@
 //   SVGString is used only for boxing values for non-list string property
 //   SVGAnimatedString,
 //   and not used for SVGStringList.
-class SVGStringList final : public SVGPropertyHelper<SVGStringList> {
+class SVGStringListBase : public SVGPropertyBase {
  public:
   typedef SVGStringListTearOff TearOffType;
 
-  static SVGStringList* Create() { return new SVGStringList(); }
-
-  ~SVGStringList() override;
+  ~SVGStringListBase() override;
 
   const Vector<String>& Values() const { return values_; }
 
@@ -76,8 +74,7 @@
   void ReplaceItem(const String&, size_t, ExceptionState&);
 
   // SVGPropertyBase:
-  SVGParsingError SetValueAsString(const String&);
-  String ValueAsString() const override;
+  virtual SVGParsingError SetValueAsString(const String&) = 0;
 
   void Add(SVGPropertyBase*, SVGElement*) override;
   void CalculateAnimatedValue(SVGAnimationElement*,
@@ -91,16 +88,48 @@
 
   static AnimatedPropertyType ClassType() { return kAnimatedStringList; }
 
- private:
-  SVGStringList();
+  SVGPropertyBase* CloneForAnimation(const String& value) const override {
+    NOTREACHED();
+    return nullptr;
+  }
+
+  AnimatedPropertyType GetType() const override { return ClassType(); }
+
+ protected:
+  SVGParsingError SetValueAsStringWithDelimiter(const String& data,
+                                                char list_delimiter);
+  String ValueAsStringWithDelimiter(char list_delimiter) const;
 
   template <typename CharType>
-  void ParseInternal(const CharType*& ptr, const CharType* end);
+  void ParseInternal(const CharType*& ptr,
+                     const CharType* end,
+                     char list_delimiter);
   bool CheckIndexBound(size_t, ExceptionState&);
 
   Vector<String> values_;
 };
 
+template <char list_delimiter>
+class SVGStringList final : public SVGStringListBase {
+ public:
+  static SVGStringList<list_delimiter>* Create() {
+    return new SVGStringList<list_delimiter>();
+  }
+  ~SVGStringList() override = default;
+
+  SVGParsingError SetValueAsString(const String& data) override {
+    return SVGStringListBase::SetValueAsStringWithDelimiter(data,
+                                                            list_delimiter);
+  }
+
+  String ValueAsString() const override {
+    return SVGStringListBase::ValueAsStringWithDelimiter(list_delimiter);
+  }
+
+ private:
+  SVGStringList() = default;
+};
+
 }  // namespace blink
 
 #endif  // THIRD_PARTY_BLINK_RENDERER_CORE_SVG_SVG_STRING_LIST_H_
diff --git a/third_party/blink/renderer/core/svg/svg_string_list_tear_off.cc b/third_party/blink/renderer/core/svg/svg_string_list_tear_off.cc
index 356a435..667994f 100644
--- a/third_party/blink/renderer/core/svg/svg_string_list_tear_off.cc
+++ b/third_party/blink/renderer/core/svg/svg_string_list_tear_off.cc
@@ -33,10 +33,11 @@
 namespace blink {
 
 SVGStringListTearOff::SVGStringListTearOff(
-    SVGStringList* target,
+    SVGStringListBase* target,
     SVGAnimatedPropertyBase* binding,
     PropertyIsAnimValType property_is_anim_val)
-    : SVGPropertyTearOff<SVGStringList>(target, binding, property_is_anim_val) {
-}
+    : SVGPropertyTearOff<SVGStringListBase>(target,
+                                            binding,
+                                            property_is_anim_val) {}
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/core/svg/svg_string_list_tear_off.h b/third_party/blink/renderer/core/svg/svg_string_list_tear_off.h
index 0860fb5..ea421fe2 100644
--- a/third_party/blink/renderer/core/svg/svg_string_list_tear_off.h
+++ b/third_party/blink/renderer/core/svg/svg_string_list_tear_off.h
@@ -36,12 +36,12 @@
 
 namespace blink {
 
-class SVGStringListTearOff : public SVGPropertyTearOff<SVGStringList> {
+class SVGStringListTearOff : public SVGPropertyTearOff<SVGStringListBase> {
   DEFINE_WRAPPERTYPEINFO();
 
  public:
   static SVGStringListTearOff* Create(
-      SVGStringList* target,
+      SVGStringListBase* target,
       SVGAnimatedPropertyBase* binding,
       PropertyIsAnimValType property_is_anim_val) {
     return new SVGStringListTearOff(target, binding, property_is_anim_val);
@@ -127,7 +127,7 @@
   }
 
  protected:
-  SVGStringListTearOff(SVGStringList*,
+  SVGStringListTearOff(SVGStringListBase*,
                        SVGAnimatedPropertyBase* binding,
                        PropertyIsAnimValType);
 };
diff --git a/third_party/blink/renderer/core/svg/svg_tests.cc b/third_party/blink/renderer/core/svg/svg_tests.cc
index 7a9f9127..ff2223e 100644
--- a/third_party/blink/renderer/core/svg/svg_tests.cc
+++ b/third_party/blink/renderer/core/svg/svg_tests.cc
@@ -29,11 +29,11 @@
 
 SVGTests::SVGTests(SVGElement* context_element)
     : required_extensions_(
-          SVGStaticStringList::Create(context_element,
-                                      SVGNames::requiredExtensionsAttr)),
+          SVGStaticStringList::Create<' '>(context_element,
+                                           SVGNames::requiredExtensionsAttr)),
       system_language_(
-          SVGStaticStringList::Create(context_element,
-                                      SVGNames::systemLanguageAttr)) {
+          SVGStaticStringList::Create<','>(context_element,
+                                           SVGNames::systemLanguageAttr)) {
   DCHECK(context_element);
 
   context_element->AddToPropertyMap(required_extensions_);
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_html.idl b/third_party/blink/renderer/core/trustedtypes/trusted_html.idl
index 7afcc83..995d8149 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_html.idl
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_html.idl
@@ -7,7 +7,7 @@
 typedef (DOMString or TrustedHTML) HTMLString;
 
 [
-    Exposed=(Window,Worker),
+    Exposed=Window,
     RuntimeEnabled=TrustedDOMTypes
 ] interface TrustedHTML {
     stringifier;
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_script.idl b/third_party/blink/renderer/core/trustedtypes/trusted_script.idl
index 4e1bcdc..a8f86e4 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_script.idl
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_script.idl
@@ -7,7 +7,7 @@
 typedef (DOMString or TrustedScript) ScriptString;
 
 [
-    Exposed=(Window,Worker),
+    Exposed=Window,
     RuntimeEnabled=TrustedDOMTypes
 ] interface TrustedScript {
     stringifier;
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_script_url.idl b/third_party/blink/renderer/core/trustedtypes/trusted_script_url.idl
index 8beb2b91..3a4faee 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_script_url.idl
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_script_url.idl
@@ -7,7 +7,7 @@
 typedef (DOMString or TrustedScriptURL) ScriptURLString;
 
 [
-    Exposed=(Window,Worker),
+    Exposed=Window,
     RuntimeEnabled=TrustedDOMTypes
 ] interface TrustedScriptURL {
     stringifier;
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.idl b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.idl
index 3a0cfe49..fb1ac33 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.idl
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy.idl
@@ -7,7 +7,7 @@
 typedef (DOMString or TrustedHTML or TrustedScript or TrustedScriptURL or TrustedURL) TrustedString;
 
 [
-    Exposed=(Window),
+    Exposed=Window,
     RuntimeEnabled=TrustedDOMTypes
 ] interface TrustedTypePolicy {
     readonly attribute DOMString name;
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.idl b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.idl
index e42e08e..8b6a3db 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.idl
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_type_policy_factory.idl
@@ -5,7 +5,7 @@
 // https://github.com/wicg/trusted-types
 
 [
-    Exposed=(Window),
+    Exposed=Window,
     RuntimeEnabled=TrustedDOMTypes
 ] interface TrustedTypePolicyFactory {
     [RaisesException] TrustedTypePolicy createPolicy(DOMString policyName, TrustedTypePolicyOptions policyOptions, optional boolean exposed = false);
diff --git a/third_party/blink/renderer/core/trustedtypes/trusted_url.idl b/third_party/blink/renderer/core/trustedtypes/trusted_url.idl
index ca0d585..b611563 100644
--- a/third_party/blink/renderer/core/trustedtypes/trusted_url.idl
+++ b/third_party/blink/renderer/core/trustedtypes/trusted_url.idl
@@ -7,7 +7,7 @@
 typedef (USVString or TrustedURL) URLString;
 
 [
-    Exposed=(Window,Worker),
+    Exposed=Window,
     RuntimeEnabled=TrustedDOMTypes
 ] interface TrustedURL {
     stringifier;
diff --git a/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.h b/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.h
index 12fbe5e..10369bc 100644
--- a/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.h
+++ b/third_party/blink/renderer/core/workers/dedicated_worker_messaging_proxy.h
@@ -9,7 +9,7 @@
 #include "base/macros.h"
 #include "base/memory/scoped_refptr.h"
 #include "base/optional.h"
-#include "third_party/blink/public/mojom/message_port/message_port.mojom-blink.h"
+#include "third_party/blink/public/mojom/messaging/message_port.mojom-blink.h"
 #include "third_party/blink/renderer/core/core_export.h"
 #include "third_party/blink/renderer/core/messaging/message_port.h"
 #include "third_party/blink/renderer/core/workers/global_scope_creation_params.h"
diff --git a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
index 8bbd71d0..8ca15fa5 100644
--- a/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
+++ b/third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.cc
@@ -5,7 +5,6 @@
 #include "third_party/blink/renderer/core/workers/worker_or_worklet_global_scope.h"
 
 #include "third_party/blink/public/platform/task_type.h"
-#include "third_party/blink/renderer/bindings/core/v8/v8_abstract_event_handler.h"
 #include "third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h"
 #include "third_party/blink/renderer/core/dom/events/event_queue.h"
 #include "third_party/blink/renderer/core/frame/deprecation.h"
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
index 278de3a..c1659d59 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager.cc
@@ -4,15 +4,12 @@
 
 #include "third_party/blink/renderer/modules/background_fetch/background_fetch_manager.h"
 
-#include "base/memory/scoped_refptr.h"
 #include "base/metrics/histogram_macros.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h"
 #include "third_party/blink/renderer/bindings/core/v8/request_or_usv_string.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise_resolver.h"
 #include "third_party/blink/renderer/bindings/modules/v8/request_or_usv_string_or_request_or_usv_string_sequence.h"
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
-#include "third_party/blink/renderer/core/fetch/body.h"
-#include "third_party/blink/renderer/core/fetch/body_stream_buffer.h"
 #include "third_party/blink/renderer/core/fetch/request.h"
 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
 #include "third_party/blink/renderer/core/frame/deprecation.h"
@@ -27,7 +24,6 @@
 #include "third_party/blink/renderer/platform/bindings/exception_code.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
 #include "third_party/blink/renderer/platform/bindings/v8_throw_exception.h"
-#include "third_party/blink/renderer/platform/blob/blob_data.h"
 #include "third_party/blink/renderer/platform/loader/cors/cors.h"
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_utils.h"
 #include "third_party/blink/renderer/platform/network/network_utils.h"
@@ -149,31 +145,6 @@
   return false;
 }
 
-scoped_refptr<BlobDataHandle> ExtractBlobHandle(
-    Request* request,
-    ExceptionState& exception_state) {
-  DCHECK(request);
-
-  if (request->IsBodyLocked(exception_state) == Body::BodyLocked::kLocked ||
-      request->IsBodyUsed(exception_state) == Body::BodyUsed::kUsed) {
-    DCHECK(!exception_state.HadException());
-    exception_state.ThrowTypeError("Request body is already used");
-    return nullptr;
-  }
-
-  BodyStreamBuffer* buffer = request->BodyBuffer();
-  if (!buffer)
-    return nullptr;
-
-  auto blob_handle = buffer->DrainAsBlobDataHandle(
-      BytesConsumer::BlobSizePolicy::kDisallowBlobWithInvalidSize,
-      exception_state);
-  if (exception_state.HadException())
-    return nullptr;
-
-  return blob_handle;
-}
-
 }  // namespace
 
 BackgroundFetchManager::BackgroundFetchManager(
@@ -440,16 +411,16 @@
       }
 
       DCHECK(request);
+      // TODO(crbug.com/774054): Set blob data handle when adding support for
+      // requests with body.
       request->PopulateWebServiceWorkerRequest(web_requests[i]);
-      web_requests[i].SetBlobDataHandle(
-          ExtractBlobHandle(request, exception_state));
     }
   } else if (requests.IsRequest()) {
     DCHECK(requests.GetAsRequest());
+    // TODO(crbug.com/774054): Set blob data handle when adding support for
+    // requests with body.
     web_requests.resize(1);
     requests.GetAsRequest()->PopulateWebServiceWorkerRequest(web_requests[0]);
-    web_requests[0].SetBlobDataHandle(
-        ExtractBlobHandle(requests.GetAsRequest(), exception_state));
   } else if (requests.IsUSVString()) {
     Request* request = Request::Create(script_state, requests.GetAsUSVString(),
                                        exception_state);
diff --git a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager_test.cc b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager_test.cc
index 063d42f..c962f63 100644
--- a/third_party/blink/renderer/modules/background_fetch/background_fetch_manager_test.cc
+++ b/third_party/blink/renderer/modules/background_fetch/background_fetch_manager_test.cc
@@ -14,7 +14,6 @@
 #include "third_party/blink/renderer/core/fetch/request_init.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
 #include "third_party/blink/renderer/platform/bindings/script_state.h"
-#include "third_party/blink/renderer/platform/blob/blob_data.h"
 
 namespace blink {
 
@@ -176,48 +175,4 @@
             ESErrorType::kTypeError);
 }
 
-TEST_F(BackgroundFetchManagerTest, BlobsExtracted) {
-  V8TestingScope scope;
-
-  KURL image_url("https://www.example.com/my_image.png");
-  KURL icon_url("https://www.example.com/my_icon.jpg");
-
-  // Create first request with a body.
-  String body_text = "cat_pic";
-  RequestInit request_init;
-  request_init.setMethod("POST");
-  request_init.setBody(blink::ScriptValue(
-      scope.GetScriptState(), ToV8(body_text, scope.GetScriptState())));
-  Request* image_request =
-      Request::Create(scope.GetScriptState(), image_url.GetString(),
-                      request_init, scope.GetExceptionState());
-  ASSERT_FALSE(scope.GetExceptionState().HadException());
-  ASSERT_TRUE(image_request);
-  ASSERT_TRUE(image_request->HasBody());
-
-  // Create second request without a body.
-  RequestOrUSVString icon_request =
-      RequestOrUSVString::FromUSVString(icon_url.GetString());
-
-  // Create a request sequence with both requests.
-  HeapVector<RequestOrUSVString> request_sequence;
-  request_sequence.push_back(RequestOrUSVString::FromRequest(image_request));
-  request_sequence.push_back(icon_request);
-
-  RequestOrUSVStringOrRequestOrUSVStringSequence requests =
-      RequestOrUSVStringOrRequestOrUSVStringSequence::
-          FromRequestOrUSVStringSequence(request_sequence);
-
-  // Extract the blobs.
-  auto web_requests = CreateWebRequestVector(scope, requests);
-  ASSERT_FALSE(scope.GetExceptionState().HadException());
-
-  ASSERT_EQ(web_requests.size(), 2u);
-
-  ASSERT_TRUE(web_requests[0].GetBlobDataHandle());
-  EXPECT_EQ(web_requests[0].GetBlobDataHandle()->size(), body_text.length());
-
-  EXPECT_FALSE(web_requests[1].GetBlobDataHandle());
-}
-
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc b/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
index 9a0acee7..22e969f3 100644
--- a/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
+++ b/third_party/blink/renderer/modules/encryptedmedia/navigator_request_media_key_system_access.cc
@@ -19,6 +19,7 @@
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
 #include "third_party/blink/renderer/core/frame/deprecation.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/core/inspector/console_message.h"
 #include "third_party/blink/renderer/modules/encryptedmedia/encrypted_media_utils.h"
 #include "third_party/blink/renderer/modules/encryptedmedia/media_key_session.h"
diff --git a/third_party/blink/renderer/modules/filesystem/window_file_system.idl b/third_party/blink/renderer/modules/filesystem/window_file_system.idl
index 39bd2744..3259df9f 100644
--- a/third_party/blink/renderer/modules/filesystem/window_file_system.idl
+++ b/third_party/blink/renderer/modules/filesystem/window_file_system.idl
@@ -40,8 +40,6 @@
 
     // https://github.com/WICG/writable-files/blob/master/EXPLAINER.md
     // TODO(crbug.com/878581): This needs some kind of options dictionary.
-    // TODO(crbug.com/878566): This should be SecureContext, but that is
-    //     currently broken.
-    [RuntimeEnabled=WritableFiles, CallWith=ScriptState]
+    [RuntimeEnabled=WritableFiles, CallWith=ScriptState, SecureContext]
     Promise<(FileSystemBaseHandle or sequence<FileSystemBaseHandle>)> chooseFileSystemEntries();
 };
diff --git a/third_party/blink/renderer/modules/notifications/notification_data.h b/third_party/blink/renderer/modules/notifications/notification_data.h
index 0dcb0f02..2e21e5b 100644
--- a/third_party/blink/renderer/modules/notifications/notification_data.h
+++ b/third_party/blink/renderer/modules/notifications/notification_data.h
@@ -5,7 +5,7 @@
 #ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_NOTIFICATIONS_NOTIFICATION_DATA_H_
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_NOTIFICATIONS_NOTIFICATION_DATA_H_
 
-#include "third_party/blink/public/platform/modules/notifications/notification.mojom-blink.h"
+#include "third_party/blink/public/mojom/notifications/notification.mojom-blink.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 
 namespace WTF {
diff --git a/third_party/blink/renderer/modules/notifications/notification_manager.cc b/third_party/blink/renderer/modules/notifications/notification_manager.cc
index 21d3be4..60fd902 100644
--- a/third_party/blink/renderer/modules/notifications/notification_manager.cc
+++ b/third_party/blink/renderer/modules/notifications/notification_manager.cc
@@ -5,8 +5,8 @@
 #include "third_party/blink/renderer/modules/notifications/notification_manager.h"
 
 #include "services/service_manager/public/cpp/interface_provider.h"
+#include "third_party/blink/public/mojom/notifications/notification.mojom-blink.h"
 #include "third_party/blink/public/platform/interface_provider.h"
-#include "third_party/blink/public/platform/modules/notifications/notification.mojom-blink.h"
 #include "third_party/blink/public/platform/modules/permissions/permission.mojom-blink.h"
 #include "third_party/blink/public/platform/modules/permissions/permission_status.mojom-blink.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_registration.h"
diff --git a/third_party/blink/renderer/modules/notifications/notification_resources_loader.h b/third_party/blink/renderer/modules/notifications/notification_resources_loader.h
index f9b3e5fa..1e8eb32 100644
--- a/third_party/blink/renderer/modules/notifications/notification_resources_loader.h
+++ b/third_party/blink/renderer/modules/notifications/notification_resources_loader.h
@@ -6,7 +6,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_NOTIFICATIONS_NOTIFICATION_RESOURCES_LOADER_H_
 
 #include <memory>
-#include "third_party/blink/public/platform/modules/notifications/notification.mojom-blink.h"
+#include "third_party/blink/public/mojom/notifications/notification.mojom-blink.h"
 #include "third_party/blink/renderer/modules/modules_export.h"
 #include "third_party/blink/renderer/modules/notifications/notification_image_loader.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
diff --git a/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.h b/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.h
index 4af07fde..38c1ad0 100644
--- a/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.h
+++ b/third_party/blink/renderer/modules/notifications/service_worker_registration_notifications.h
@@ -7,7 +7,7 @@
 
 #include <memory>
 #include "base/memory/scoped_refptr.h"
-#include "third_party/blink/public/platform/modules/notifications/notification.mojom-blink.h"
+#include "third_party/blink/public/mojom/notifications/notification.mojom-blink.h"
 #include "third_party/blink/renderer/bindings/core/v8/script_promise.h"
 #include "third_party/blink/renderer/core/dom/context_lifecycle_observer.h"
 #include "third_party/blink/renderer/platform/heap/garbage_collected.h"
diff --git a/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.h b/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.h
index ac0329b..c4a435e 100644
--- a/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.h
+++ b/third_party/blink/renderer/modules/sensor/sensor_proxy_impl.h
@@ -9,6 +9,7 @@
 
 #include "mojo/public/cpp/bindings/binding.h"
 #include "third_party/blink/renderer/platform/heap/handle.h"
+#include "third_party/blink/renderer/platform/timer.h"
 #include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
index cac97ac9..3bea7b4 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope.cc
@@ -136,8 +136,7 @@
     InstalledScriptsManager::ScriptStatus status =
         installed_scripts_manager->GetScriptData(script_url, &script_data);
     if (status == InstalledScriptsManager::ScriptStatus::kFailed) {
-      // This eventually terminates the worker thread.
-      ReportingProxy().DidEvaluateClassicScript(false);
+      close();
       return;
     }
 
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h
index 9109635..f93376a52 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_client.h
@@ -32,7 +32,7 @@
 #define THIRD_PARTY_BLINK_RENDERER_MODULES_SERVICE_WORKER_SERVICE_WORKER_GLOBAL_SCOPE_CLIENT_H_
 
 #include <memory>
-#include "third_party/blink/public/common/message_port/transferable_message.h"
+#include "third_party/blink/public/common/messaging/transferable_message.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom-blink.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_claim_callbacks.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_clients_info.h"
diff --git a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
index c2287906..e6a8d2b 100644
--- a/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
+++ b/third_party/blink/renderer/modules/service_worker/service_worker_global_scope_proxy.cc
@@ -34,9 +34,9 @@
 #include <utility>
 
 #include "base/memory/ptr_util.h"
+#include "third_party/blink/public/mojom/notifications/notification.mojom-blink.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_client.mojom-blink.h"
 #include "third_party/blink/public/mojom/service_worker/service_worker_event_status.mojom-blink.h"
-#include "third_party/blink/public/platform/modules/notifications/notification.mojom-blink.h"
 #include "third_party/blink/public/platform/modules/notifications/web_notification_data.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_request.h"
 #include "third_party/blink/public/web/modules/service_worker/web_service_worker_context_client.h"
@@ -668,9 +668,30 @@
 }
 
 void ServiceWorkerGlobalScopeProxy::DidCloseWorkerGlobalScope() {
-  // This should never be called because close() is not defined in
-  // ServiceWorkerGlobalScope.
-  NOTREACHED();
+  DCHECK(WorkerGlobalScope()->IsContextThread());
+  // close() is not web-exposed. This is called when ServiceWorkerGlobalScope
+  // internally requests close() due to failure on startup when installed
+  // scripts couldn't be read.
+  //
+  // This may look like a roundabout way to terminate the thread, but close()
+  // seems like the standard way to initiate termination from inside the thread.
+
+  // Tell ServiceWorkerContextClient about the failure. The generic
+  // WorkerContextFailedToStart() wouldn't make sense because
+  // WorkerContextStarted() was already called.
+  Client().FailedToLoadInstalledScript();
+
+  // ServiceWorkerGlobalScope expects us to terminate the thread, so request
+  // that here.
+  PostCrossThreadTask(
+      *parent_execution_context_task_runners_->Get(TaskType::kInternalDefault),
+      FROM_HERE,
+      CrossThreadBind(&WebEmbeddedWorkerImpl::TerminateWorkerContext,
+                      CrossThreadUnretained(embedded_worker_)));
+
+  // NOTE: WorkerThread calls WillDestroyWorkerGlobalScope() synchronously after
+  // this function returns, since it calls DidCloseWorkerGlobalScope() then
+  // PrepareForShutdownOnWorkerThread().
 }
 
 void ServiceWorkerGlobalScopeProxy::WillDestroyWorkerGlobalScope() {
@@ -682,7 +703,7 @@
 }
 
 void ServiceWorkerGlobalScopeProxy::DidTerminateWorkerThread() {
-  // This should be called after WillDestroyWorkerGlobalScope().
+  // This must be called after WillDestroyWorkerGlobalScope().
   DCHECK(!worker_global_scope_);
   Client().WorkerContextDestroyed();
 }
@@ -709,6 +730,7 @@
 }
 
 void ServiceWorkerGlobalScopeProxy::TerminateWorkerContext() {
+  DCHECK(IsMainThread());
   embedded_worker_->TerminateWorkerContext();
 }
 
diff --git a/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc b/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
index 231bb628..e2de418 100644
--- a/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
+++ b/third_party/blink/renderer/modules/service_worker/web_embedded_worker_impl_test.cc
@@ -7,7 +7,7 @@
 #include <memory>
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_installed_scripts_manager.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_network_provider.h"
 #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_provider.h"
diff --git a/third_party/blink/renderer/modules/storage/storage_namespace_controller.cc b/third_party/blink/renderer/modules/storage/storage_namespace_controller.cc
index 9ee5d28..fda4360 100644
--- a/third_party/blink/renderer/modules/storage/storage_namespace_controller.cc
+++ b/third_party/blink/renderer/modules/storage/storage_namespace_controller.cc
@@ -10,6 +10,7 @@
 #include "third_party/blink/public/platform/web_storage_namespace.h"
 #include "third_party/blink/public/web/web_view_client.h"
 #include "third_party/blink/renderer/core/frame/content_settings_client.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/modules/storage/inspector_dom_storage_agent.h"
 #include "third_party/blink/renderer/modules/storage/storage_namespace.h"
 
diff --git a/third_party/blink/renderer/modules/wake_lock/wake_lock.cc b/third_party/blink/renderer/modules/wake_lock/wake_lock.cc
index 109ce86..ea8ba308 100644
--- a/third_party/blink/renderer/modules/wake_lock/wake_lock.cc
+++ b/third_party/blink/renderer/modules/wake_lock/wake_lock.cc
@@ -11,6 +11,7 @@
 #include "third_party/blink/renderer/core/dom/dom_exception.h"
 #include "third_party/blink/renderer/core/dom/events/event.h"
 #include "third_party/blink/renderer/core/execution_context/execution_context.h"
+#include "third_party/blink/renderer/core/frame/local_frame.h"
 #include "third_party/blink/renderer/modules/wake_lock/wake_lock_request.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 
diff --git a/third_party/blink/renderer/modules/webdatabase/database_tracker.cc b/third_party/blink/renderer/modules/webdatabase/database_tracker.cc
index b632e5f8..80cce50 100644
--- a/third_party/blink/renderer/modules/webdatabase/database_tracker.cc
+++ b/third_party/blink/renderer/modules/webdatabase/database_tracker.cc
@@ -216,7 +216,7 @@
       for (Database* database : *name_database_set.value) {
         ExecutionContext* context = database->GetExecutionContext();
         DCHECK(context->IsDocument());
-        if (ToDocument(context)->GetFrame()->GetPage() == page)
+        if (ToDocument(context)->GetPage() == page)
           callback.Run(database);
       }
     }
diff --git a/third_party/blink/renderer/platform/bindings/callback_function_base.cc b/third_party/blink/renderer/platform/bindings/callback_function_base.cc
index 3579f58..07c8a4c 100644
--- a/third_party/blink/renderer/platform/bindings/callback_function_base.cc
+++ b/third_party/blink/renderer/platform/bindings/callback_function_base.cc
@@ -7,7 +7,7 @@
 namespace blink {
 
 CallbackFunctionBase::CallbackFunctionBase(
-    v8::Local<v8::Function> callback_function) {
+    v8::Local<v8::Object> callback_function) {
   DCHECK(!callback_function.IsEmpty());
 
   callback_relevant_script_state_ =
diff --git a/third_party/blink/renderer/platform/bindings/callback_function_base.h b/third_party/blink/renderer/platform/bindings/callback_function_base.h
index 4acb4fd5..cc38447a 100644
--- a/third_party/blink/renderer/platform/bindings/callback_function_base.h
+++ b/third_party/blink/renderer/platform/bindings/callback_function_base.h
@@ -31,9 +31,14 @@
 
   virtual void Trace(blink::Visitor* visitor);
 
+  v8::Local<v8::Object> CallbackObject() {
+    return callback_function_.NewLocal(GetIsolate());
+  }
+
   v8::Isolate* GetIsolate() const {
     return callback_relevant_script_state_->GetIsolate();
   }
+
   ScriptState* CallbackRelevantScriptState() {
     return callback_relevant_script_state_;
   }
@@ -42,16 +47,18 @@
   bool IsConstructor() const { return CallbackFunction()->IsConstructor(); }
 
  protected:
-  explicit CallbackFunctionBase(v8::Local<v8::Function>);
+  explicit CallbackFunctionBase(v8::Local<v8::Object>);
 
   v8::Local<v8::Function> CallbackFunction() const {
-    return callback_function_.NewLocal(GetIsolate());
+    return callback_function_.NewLocal(GetIsolate()).As<v8::Function>();
   }
   ScriptState* IncumbentScriptState() { return incumbent_script_state_; }
 
  private:
   // The "callback function type" value.
-  TraceWrapperV8Reference<v8::Function> callback_function_;
+  // Use v8::Object instead of v8::Function in order to handle
+  // [TreatNonObjectAsNull].
+  TraceWrapperV8Reference<v8::Object> callback_function_;
   // The associated Realm of the callback function type value.
   Member<ScriptState> callback_relevant_script_state_;
   // The callback context, i.e. the incumbent Realm when an ECMAScript value is
@@ -92,7 +99,9 @@
 
  private:
   Member<CallbackFunctionBase> callback_function_;
-  v8::Persistent<v8::Function> v8_function_;
+  // Use v8::Object instead of v8::Function in order to handle
+  // [TreatNonObjectAsNull].
+  v8::Persistent<v8::Object> v8_function_;
 };
 
 // V8PersistentCallbackFunction<V8CallbackFunction> is a counter-part of
diff --git a/third_party/blink/renderer/platform/bindings/parkable_string.cc b/third_party/blink/renderer/platform/bindings/parkable_string.cc
index 1a8c9bb1..f80b462 100644
--- a/third_party/blink/renderer/platform/bindings/parkable_string.cc
+++ b/third_party/blink/renderer/platform/bindings/parkable_string.cc
@@ -18,16 +18,33 @@
 
 }  // namespace
 
-ParkableStringImpl::ParkableStringImpl() = default;
+ParkableStringImpl::ParkableStringImpl()
+    : ParkableStringImpl({nullptr}, ParkableState::kNotParkable) {}
 
-ParkableStringImpl::ParkableStringImpl(scoped_refptr<StringImpl>&& impl)
-    : string_(std::move(impl)), is_parked_(false) {}
+ParkableStringImpl::ParkableStringImpl(scoped_refptr<StringImpl>&& impl,
+                                       ParkableState parkable)
+    : mutex_(),
+      lock_depth_(0),
+      string_(std::move(impl)),
+      is_parked_(false),
+      is_parkable_(parkable == ParkableState::kParkable) {}
 
 ParkableStringImpl::~ParkableStringImpl() {
-  if (ParkableStringManager::ShouldPark(string_.Impl()))
+  if (is_parkable_)
     ParkableStringManager::Instance().Remove(string_.Impl());
 }
 
+void ParkableStringImpl::Lock() {
+  MutexLocker locker(mutex_);
+  lock_depth_ += 1;
+}
+
+void ParkableStringImpl::Unlock() {
+  MutexLocker locker(mutex_);
+  DCHECK_GT(lock_depth_, 0);
+  lock_depth_ -= 1;
+}
+
 bool ParkableStringImpl::Is8Bit() const {
   return string_.Is8Bit();
 }
@@ -37,6 +54,7 @@
 }
 
 const String& ParkableStringImpl::ToString() {
+  MutexLocker locker(mutex_);
   Unpark();
   return string_;
 }
@@ -46,6 +64,12 @@
 }
 
 bool ParkableStringImpl::Park() {
+  MutexLocker locker(mutex_);
+  DCHECK(is_parkable_);
+
+  if (lock_depth_ != 0)
+    return false;
+
   // Cannot park strings with several references.
   if (string_.Impl()->HasOneRef()) {
     RecordParkingAction(ParkingAction::kParkedInBackground);
@@ -55,6 +79,7 @@
 }
 
 void ParkableStringImpl::Unpark() {
+  mutex_.AssertAcquired();
   if (!is_parked_)
     return;
 
@@ -66,15 +91,27 @@
 }
 
 ParkableString::ParkableString(scoped_refptr<StringImpl>&& impl) {
-  if (ParkableStringManager::ShouldPark(impl.get())) {
+  bool is_parkable = ParkableStringManager::ShouldPark(impl.get());
+  if (is_parkable) {
     impl_ = ParkableStringManager::Instance().Add(std::move(impl));
   } else {
-    impl_ = base::MakeRefCounted<ParkableStringImpl>(std::move(impl));
+    impl_ = base::MakeRefCounted<ParkableStringImpl>(
+        std::move(impl), ParkableStringImpl::ParkableState::kNotParkable);
   }
 }
 
 ParkableString::~ParkableString() = default;
 
+void ParkableString::Lock() const {
+  if (impl_)
+    impl_->Lock();
+}
+
+void ParkableString::Unlock() const {
+  if (impl_)
+    impl_->Unlock();
+}
+
 bool ParkableString::Is8Bit() const {
   return impl_->Is8Bit();
 }
diff --git a/third_party/blink/renderer/platform/bindings/parkable_string.h b/third_party/blink/renderer/platform/bindings/parkable_string.h
index b7efdd3..1e6bab16 100644
--- a/third_party/blink/renderer/platform/bindings/parkable_string.h
+++ b/third_party/blink/renderer/platform/bindings/parkable_string.h
@@ -15,6 +15,7 @@
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/ref_counted.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "third_party/blink/renderer/platform/wtf/threading_primitives.h"
 
 // ParkableString represents a string that may be parked in memory, that it its
 // underlying memory address may change. Its content can be retrieved with the
@@ -30,6 +31,11 @@
 
 namespace blink {
 
+// A parked string is parked by calling |Park()|, and unparked by calling
+// |ToString()| on a parked string.
+// |Lock()| does *not* unpark a string, and |ToString()| must be called on
+// a single thread, the one on which the string was created. Only |Lock()|
+// and |Unlock()| can be called from any thread.
 class PLATFORM_EXPORT ParkableStringImpl final
     : public RefCounted<ParkableStringImpl> {
  public:
@@ -41,10 +47,18 @@
     kMaxValue = kUnparkedInForeground
   };
 
+  enum class ParkableState { kParkable, kNotParkable };
+
   ParkableStringImpl();
-  explicit ParkableStringImpl(scoped_refptr<StringImpl>&& impl);
+  // Not all parkable strings can actually be parked. If |parkable| is
+  // kNotParkable, then one cannot call |Park()|, and the underlying StringImpl
+  // will not move.
+  ParkableStringImpl(scoped_refptr<StringImpl>&& impl, ParkableState parkable);
   ~ParkableStringImpl();
 
+  void Lock();
+  void Unlock();
+
   // The returned string may be used as a normal one, as long as the
   // returned value (or a copy of it) is alive.
   const String& ToString();
@@ -58,29 +72,52 @@
   // A parked string cannot be accessed until it has been |Unpark()|-ed.
   // Returns true iff the string has been parked.
   bool Park();
-  // Returns true if the string is parked.
-  bool is_parked() const { return is_parked_; }
+  // Returns true iff the string can be parked.
+  bool is_parkable() const { return is_parkable_; }
 
  private:
   void Unpark();
+  // Returns true if the string is parked.
+  bool is_parked() const { return is_parked_; }
 
+  Mutex mutex_;  // protects the variables below.
+  int lock_depth_;
   String string_;
   bool is_parked_;
 
+  const bool is_parkable_;
+
+  FRIEND_TEST_ALL_PREFIXES(ParkableStringTest, Park);
+  FRIEND_TEST_ALL_PREFIXES(ParkableStringTest, Unpark);
+  FRIEND_TEST_ALL_PREFIXES(ParkableStringTest, LockUnlock);
+  FRIEND_TEST_ALL_PREFIXES(ParkableStringTest, LockParkedString);
+  FRIEND_TEST_ALL_PREFIXES(ParkableStringTest, TableSimple);
+  FRIEND_TEST_ALL_PREFIXES(ParkableStringTest, TableMultiple);
   DISALLOW_COPY_AND_ASSIGN(ParkableStringImpl);
 };
 
 class PLATFORM_EXPORT ParkableString final {
  public:
-  ParkableString() : impl_(base::MakeRefCounted<ParkableStringImpl>(nullptr)) {}
+  ParkableString() : impl_(base::MakeRefCounted<ParkableStringImpl>()) {}
   explicit ParkableString(scoped_refptr<StringImpl>&& impl);
   ParkableString(const ParkableString& rhs) : impl_(rhs.impl_) {}
   ~ParkableString();
 
+  // Locks a string. A string is unlocked when the number of Lock()/Unlock()
+  // calls match. A locked string cannot be parked.
+  // Can be called from any thread.
+  void Lock() const;
+
+  // Unlocks a string.
+  // Can be called from any thread.
+  void Unlock() const;
+
   // See the matching String methods.
   bool Is8Bit() const;
   bool IsNull() const;
   unsigned length() const { return impl_->length(); }
+  bool is_parkable() const { return impl_ && impl_->is_parkable(); }
+
   ParkableStringImpl* Impl() const { return impl_.get(); }
   // Returns an unparked version of the string.
   // The string is guaranteed to be valid for
diff --git a/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc b/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc
index 8b62019..1b7091b 100644
--- a/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc
+++ b/third_party/blink/renderer/platform/bindings/parkable_string_manager.cc
@@ -61,8 +61,8 @@
   if (it != table_.end())
     return it->value;
 
-  auto new_parkable_string =
-      base::MakeRefCounted<ParkableStringImpl>(std::move(string));
+  auto new_parkable_string = base::MakeRefCounted<ParkableStringImpl>(
+      std::move(string), ParkableStringImpl::ParkableState::kParkable);
   table_.insert(raw_ptr, new_parkable_string.get());
   return new_parkable_string;
 }
diff --git a/third_party/blink/renderer/platform/bindings/parkable_string_test.cc b/third_party/blink/renderer/platform/bindings/parkable_string_test.cc
index 640307c..84e7b7b 100644
--- a/third_party/blink/renderer/platform/bindings/parkable_string_test.cc
+++ b/third_party/blink/renderer/platform/bindings/parkable_string_test.cc
@@ -13,6 +13,15 @@
 
 namespace blink {
 
+namespace {
+
+String MakeLargeString() {
+  std::vector<char> data(20000, 'a');
+  return String(String(data.data(), data.size()).ReleaseImpl());
+}
+
+}  // namespace
+
 class ParkableStringTest : public ::testing::Test {
  protected:
   void SetUp() override {
@@ -28,6 +37,7 @@
   EXPECT_TRUE(parkable_abc.Is8Bit());
   EXPECT_EQ(3u, parkable_abc.length());
   EXPECT_EQ(3u, parkable_abc.CharactersSizeInBytes());
+  EXPECT_FALSE(parkable_abc.is_parkable());  // Small strings are not parkable.
 
   EXPECT_EQ(String("abc"), parkable_abc.ToString());
   ParkableString copy = parkable_abc;
@@ -37,17 +47,21 @@
 TEST_F(ParkableStringTest, Park) {
   base::HistogramTester histogram_tester;
 
-  ParkableString parkable(String("abc").Impl());
-  EXPECT_FALSE(parkable.Impl()->is_parked());
-  EXPECT_TRUE(parkable.Impl()->Park());
-  EXPECT_TRUE(parkable.Impl()->is_parked());
+  {
+    ParkableString parkable(MakeLargeString().ReleaseImpl());
+    EXPECT_TRUE(parkable.is_parkable());
+    EXPECT_FALSE(parkable.Impl()->is_parked());
+    EXPECT_TRUE(parkable.Impl()->Park());
+    EXPECT_TRUE(parkable.Impl()->is_parked());
+  }
 
+  String large_string = MakeLargeString();
+  ParkableString parkable(large_string.Impl());
+  EXPECT_TRUE(parkable.is_parkable());
   // Not the only one to have a reference to the string.
-  String abc("abc");
-  ParkableString parkable2(abc.Impl());
-  EXPECT_FALSE(parkable2.Impl()->Park());
-  abc = String();
-  EXPECT_TRUE(parkable2.Impl()->Park());
+  EXPECT_FALSE(parkable.Impl()->Park());
+  large_string = String();
+  EXPECT_TRUE(parkable.Impl()->Park());
 
   histogram_tester.ExpectBucketCount(
       "Memory.MovableStringParkingAction",
@@ -58,13 +72,15 @@
 TEST_F(ParkableStringTest, Unpark) {
   base::HistogramTester histogram_tester;
 
-  ParkableString parkable(String("abc").Impl());
+  ParkableString parkable(MakeLargeString().Impl());
+  String unparked_copy = parkable.ToString().IsolatedCopy();
+  EXPECT_TRUE(parkable.is_parkable());
   EXPECT_FALSE(parkable.Impl()->is_parked());
   EXPECT_TRUE(parkable.Impl()->Park());
   EXPECT_TRUE(parkable.Impl()->is_parked());
 
   String unparked = parkable.ToString();
-  EXPECT_EQ(String("abc"), unparked);
+  EXPECT_EQ(unparked_copy, unparked);
   EXPECT_FALSE(parkable.Impl()->is_parked());
 
   histogram_tester.ExpectTotalCount("Memory.MovableStringParkingAction", 2);
@@ -76,6 +92,50 @@
       ParkableStringImpl::ParkingAction::kUnparkedInForeground, 1);
 }
 
+TEST_F(ParkableStringTest, LockUnlock) {
+  ParkableString parkable(MakeLargeString().Impl());
+  ParkableStringImpl* impl = parkable.Impl();
+  EXPECT_EQ(0, impl->lock_depth_);
+
+  parkable.Lock();
+  EXPECT_EQ(1, impl->lock_depth_);
+  parkable.Lock();
+  parkable.Unlock();
+  EXPECT_EQ(1, impl->lock_depth_);
+  parkable.Unlock();
+  EXPECT_EQ(0, impl->lock_depth_);
+
+  parkable.Lock();
+  EXPECT_FALSE(impl->Park());
+  parkable.Unlock();
+  EXPECT_TRUE(impl->Park());
+
+  std::thread t([&]() { parkable.Lock(); });
+  t.join();
+  EXPECT_FALSE(impl->Park());
+  parkable.Unlock();
+  EXPECT_TRUE(impl->Park());
+}
+
+TEST_F(ParkableStringTest, LockParkedString) {
+  ParkableString parkable(MakeLargeString().Impl());
+  ParkableStringImpl* impl = parkable.Impl();
+  EXPECT_EQ(0, impl->lock_depth_);
+  EXPECT_TRUE(impl->Park());
+
+  parkable.Lock();  // Locking doesn't unpark.
+  EXPECT_TRUE(impl->is_parked());
+  parkable.ToString();
+  EXPECT_FALSE(impl->is_parked());
+  EXPECT_EQ(1, impl->lock_depth_);
+
+  EXPECT_FALSE(impl->Park());
+  parkable.Unlock();
+  EXPECT_EQ(0, impl->lock_depth_);
+  EXPECT_TRUE(impl->Park());
+  EXPECT_TRUE(impl->is_parked());
+}
+
 TEST_F(ParkableStringTest, TableSimple) {
   base::HistogramTester histogram_tester;
 
diff --git a/third_party/blink/renderer/platform/bindings/string_resource.h b/third_party/blink/renderer/platform/bindings/string_resource.h
index 06a0b1b2..96a5a85d 100644
--- a/third_party/blink/renderer/platform/bindings/string_resource.h
+++ b/third_party/blink/renderer/platform/bindings/string_resource.h
@@ -164,8 +164,11 @@
     DCHECK(!parkable_string_.Is8Bit());
   }
 
-  // V8 external resources are "compressible", not "parkable".
-  bool IsCompressible() const override { return true; }
+  bool IsCacheable() const override { return !parkable_string_.is_parkable(); }
+
+  void Lock() const override { parkable_string_.Lock(); }
+
+  void Unlock() const override { parkable_string_.Unlock(); }
 
   size_t length() const override { return parkable_string_.length(); }
 
@@ -185,8 +188,11 @@
     DCHECK(parkable_string_.Is8Bit());
   }
 
-  // V8 external resources are "compressible", not "parkable".
-  bool IsCompressible() const override { return true; }
+  bool IsCacheable() const override { return !parkable_string_.is_parkable(); }
+
+  void Lock() const override { parkable_string_.Lock(); }
+
+  void Unlock() const override { parkable_string_.Unlock(); }
 
   size_t length() const override { return parkable_string_.length(); }
 
diff --git a/third_party/blink/renderer/platform/bindings/v8_private_property.h b/third_party/blink/renderer/platform/bindings/v8_private_property.h
index d74a5d3..38d05de1 100644
--- a/third_party/blink/renderer/platform/bindings/v8_private_property.h
+++ b/third_party/blink/renderer/platform/bindings/v8_private_property.h
@@ -51,8 +51,8 @@
   X(SameObject, PerformanceLongTaskTimingAttribution) \
   X(SameObject, PushManagerSupportedContentEncodings) \
   X(V8ErrorHandler, ErrorHandler)                     \
-  X(V8EventListenerOrEventHandler, AttributeListener) \
-  X(V8EventListenerOrEventHandler, Listener)          \
+  X(CustomWrappable, EventHandler)                    \
+  X(CustomWrappable, EventListener)                   \
   SCRIPT_PROMISE_PROPERTIES(X, Promise)               \
   SCRIPT_PROMISE_PROPERTIES(X, Resolver)
 
diff --git a/third_party/blink/renderer/platform/cross_thread_copier.h b/third_party/blink/renderer/platform/cross_thread_copier.h
index db80737..738ceed 100644
--- a/third_party/blink/renderer/platform/cross_thread_copier.h
+++ b/third_party/blink/renderer/platform/cross_thread_copier.h
@@ -36,7 +36,7 @@
 #include "base/memory/weak_ptr.h"
 #include "mojo/public/cpp/bindings/interface_ptr_info.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
-#include "third_party/blink/public/common/message_port/message_port_channel.h"
+#include "third_party/blink/public/common/messaging/message_port_channel.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/assertions.h"
 #include "third_party/blink/renderer/platform/wtf/forward.h"
diff --git a/third_party/blink/renderer/platform/exported/web_url_response.cc b/third_party/blink/renderer/platform/exported/web_url_response.cc
index 12441a03..d2d9b33 100644
--- a/third_party/blink/renderer/platform/exported/web_url_response.cc
+++ b/third_party/blink/renderer/platform/exported/web_url_response.cc
@@ -399,6 +399,12 @@
   resource_response_->SetEncodedDataLength(length);
 }
 
+void WebURLResponse::SetIsSignedExchangeInnerResponse(
+    bool is_signed_exchange_inner_response) {
+  resource_response_->SetIsSignedExchangeInnerResponse(
+      is_signed_exchange_inner_response);
+}
+
 WebURLResponse::ExtraData* WebURLResponse::GetExtraData() const {
   scoped_refptr<ResourceResponse::ExtraData> data =
       resource_response_->GetExtraData();
diff --git a/third_party/blink/renderer/platform/fonts/linux/font_cache_linux.cc b/third_party/blink/renderer/platform/fonts/linux/font_cache_linux.cc
index 6d99346..2a7ce629 100644
--- a/third_party/blink/renderer/platform/fonts/linux/font_cache_linux.cc
+++ b/third_party/blink/renderer/platform/fonts/linux/font_cache_linux.cc
@@ -25,7 +25,7 @@
 #include "third_party/blink/renderer/platform/fonts/font_cache.h"
 
 #include "build/build_config.h"
-#include "third_party/blink/public/platform/linux/web_fallback_font.h"
+#include "third_party/blink/public/platform/linux/out_of_process_font.h"
 #include "third_party/blink/public/platform/linux/web_sandbox_support.h"
 #include "third_party/blink/public/platform/platform.h"
 #include "third_party/blink/renderer/platform/fonts/font_platform_data.h"
@@ -56,7 +56,7 @@
     const char* preferred_locale,
     FontCache::PlatformFallbackFont* fallback_font) {
   if (Platform::Current()->GetSandboxSupport()) {
-    WebFallbackFont web_fallback_font;
+    OutOfProcessFont web_fallback_font;
     Platform::Current()->GetSandboxSupport()->GetFallbackFontForCharacter(
         c, preferred_locale, &web_fallback_font);
     fallback_font->name = web_fallback_font.name;
diff --git a/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc b/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc
index b5a53cc..73b0520 100644
--- a/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc
@@ -106,11 +106,7 @@
     }
   }
 
-  viz::BeginFrameAck ack;
-  ack.source_id = args.source_id;
-  ack.sequence_number = args.sequence_number;
-  ack.has_damage = false;
-  compositor_frame_sink_->DidNotProduceFrame(ack);
+  compositor_frame_sink_->DidNotProduceFrame(viz::BeginFrameAck(args, false));
 }
 
 }  // namespace blink
diff --git a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
index c6e15aa..985fcb8 100644
--- a/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
+++ b/third_party/blink/renderer/platform/graphics/video_frame_submitter.cc
@@ -304,8 +304,7 @@
 void VideoFrameSubmitter::OnBeginFrame(const viz::BeginFrameArgs& args) {
   TRACE_EVENT0("media", "VideoFrameSubmitter::OnBeginFrame");
   DCHECK_CALLED_ON_VALID_THREAD(media_thread_checker_);
-  viz::BeginFrameAck current_begin_frame_ack =
-      viz::BeginFrameAck(args.source_id, args.sequence_number, false);
+  viz::BeginFrameAck current_begin_frame_ack(args, false);
   if (args.type == viz::BeginFrameArgs::MISSED) {
     compositor_frame_sink_->DidNotProduceFrame(current_begin_frame_ack);
     return;
diff --git a/third_party/blink/renderer/platform/loader/cors/cors.cc b/third_party/blink/renderer/platform/loader/cors/cors.cc
index 297a18e..e514903 100644
--- a/third_party/blink/renderer/platform/loader/cors/cors.cc
+++ b/third_party/blink/renderer/platform/loader/cors/cors.cc
@@ -232,6 +232,26 @@
       std::string(utf8_value.data(), utf8_value.length()));
 }
 
+bool IsNoCORSSafelistedHeader(const String& name, const String& value) {
+  DCHECK(!name.IsNull());
+  DCHECK(!value.IsNull());
+  return network::cors::IsNoCORSSafelistedHeader(WebString(name).Latin1(),
+                                                 WebString(value).Latin1());
+}
+
+Vector<String> CORSUnsafeRequestHeaderNames(const HTTPHeaderMap& headers) {
+  net::HttpRequestHeaders::HeaderVector in;
+  for (const auto& entry : headers) {
+    in.push_back(net::HttpRequestHeaders::HeaderKeyValuePair(
+        WebString(entry.key).Latin1(), WebString(entry.value).Latin1()));
+  }
+
+  Vector<String> header_names;
+  for (const auto& name : network::cors::CORSUnsafeRequestHeaderNames(in))
+    header_names.push_back(WebString::FromLatin1(name));
+  return header_names;
+}
+
 bool IsForbiddenHeaderName(const String& name) {
   CString utf8_name = name.Utf8();
   return network::cors::IsForbiddenHeader(
@@ -239,21 +259,20 @@
 }
 
 bool ContainsOnlyCORSSafelistedHeaders(const HTTPHeaderMap& header_map) {
-  for (const auto& header : header_map) {
-    if (!IsCORSSafelistedHeader(header.key, header.value))
-      return false;
-  }
-  return true;
+  Vector<String> header_names = CORSUnsafeRequestHeaderNames(header_map);
+  return header_names.IsEmpty();
 }
 
 bool ContainsOnlyCORSSafelistedOrForbiddenHeaders(
-    const HTTPHeaderMap& header_map) {
-  for (const auto& header : header_map) {
-    if (!IsCORSSafelistedHeader(header.key, header.value) &&
-        !IsForbiddenHeaderName(header.key))
-      return false;
+    const HTTPHeaderMap& headers) {
+  Vector<String> header_names;
+
+  net::HttpRequestHeaders::HeaderVector in;
+  for (const auto& entry : headers) {
+    in.push_back(net::HttpRequestHeaders::HeaderKeyValuePair(
+        WebString(entry.key).Latin1(), WebString(entry.value).Latin1()));
   }
-  return true;
+  return network::cors::CORSUnsafeNotForbiddenRequestHeaderNames(in).empty();
 }
 
 bool IsOkStatus(int status) {
diff --git a/third_party/blink/renderer/platform/loader/cors/cors.h b/third_party/blink/renderer/platform/loader/cors/cors.h
index 9d5eb4e..de2f73f4 100644
--- a/third_party/blink/renderer/platform/loader/cors/cors.h
+++ b/third_party/blink/renderer/platform/loader/cors/cors.h
@@ -11,6 +11,7 @@
 #include "services/network/public/mojom/fetch_api.mojom-shared.h"
 #include "third_party/blink/renderer/platform/platform_export.h"
 #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h"
+#include "third_party/blink/renderer/platform/wtf/vector.h"
 
 namespace blink {
 
@@ -89,6 +90,10 @@
 PLATFORM_EXPORT bool IsCORSSafelistedContentType(const String&);
 PLATFORM_EXPORT bool IsCORSSafelistedHeader(const String& name,
                                             const String& value);
+PLATFORM_EXPORT bool IsNoCORSSafelistedHeader(const String& name,
+                                              const String& value);
+PLATFORM_EXPORT Vector<String> CORSUnsafeRequestHeaderNames(
+    const HTTPHeaderMap& headers);
 PLATFORM_EXPORT bool IsForbiddenHeaderName(const String& name);
 PLATFORM_EXPORT bool ContainsOnlyCORSSafelistedHeaders(const HTTPHeaderMap&);
 PLATFORM_EXPORT bool ContainsOnlyCORSSafelistedOrForbiddenHeaders(
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
index f263954..2f37974 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_loader.cc
@@ -306,7 +306,10 @@
     return false;
   if (request.DownloadToBlob())
     return false;
-  if (resource_->GetType() != Resource::Type::kScript)
+  // If the resource type is script or MainResource (for inline scripts) fetch
+  // code cache. For others we need not fetch code cache.
+  if (resource_->GetType() != Resource::Type::kScript &&
+      resource_->GetType() != Resource::Type::kMainResource)
     return false;
   return true;
 }
diff --git a/third_party/blink/renderer/platform/loader/fetch/resource_response.h b/third_party/blink/renderer/platform/loader/fetch/resource_response.h
index a926450..a5b681d 100644
--- a/third_party/blink/renderer/platform/loader/fetch/resource_response.h
+++ b/third_party/blink/renderer/platform/loader/fetch/resource_response.h
@@ -416,6 +416,15 @@
     async_revalidation_requested_ = requested;
   }
 
+  bool IsSignedExchangeInnerResponse() const {
+    return is_signed_exchange_inner_response_;
+  }
+
+  void SetIsSignedExchangeInnerResponse(
+      bool is_signed_exchange_inner_response) {
+    is_signed_exchange_inner_response_ = is_signed_exchange_inner_response;
+  }
+
   // This method doesn't compare the all members.
   static bool Compare(const ResourceResponse&, const ResourceResponse&);
 
@@ -479,6 +488,10 @@
   // possibly be set if the load_flags indicated SUPPORT_ASYNC_REVALIDATION.
   bool async_revalidation_requested_ = false;
 
+  // True if this resource is from an inner response of a signed exchange.
+  // https://wicg.github.io/webpackage/draft-yasskin-http-origin-signed-responses.html
+  bool is_signed_exchange_inner_response_ = false;
+
   // https://fetch.spec.whatwg.org/#concept-response-type
   network::mojom::FetchResponseType response_type_ =
       network::mojom::FetchResponseType::kDefault;
diff --git a/third_party/blink/renderer/platform/mojo/revocable_binding.h b/third_party/blink/renderer/platform/mojo/revocable_binding.h
index b8d287b0..a467727 100644
--- a/third_party/blink/renderer/platform/mojo/revocable_binding.h
+++ b/third_party/blink/renderer/platform/mojo/revocable_binding.h
@@ -11,6 +11,7 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/single_thread_task_runner.h"
+#include "mojo/public/cpp/bindings/binding.h"
 #include "mojo/public/cpp/bindings/connection_error_callback.h"
 #include "mojo/public/cpp/bindings/interface_request.h"
 #include "mojo/public/cpp/bindings/lib/binding_state.h"
diff --git a/third_party/blink/renderer/platform/runtime_enabled_features.json5 b/third_party/blink/renderer/platform/runtime_enabled_features.json5
index 98aa5ece..ad012e8 100644
--- a/third_party/blink/renderer/platform/runtime_enabled_features.json5
+++ b/third_party/blink/renderer/platform/runtime_enabled_features.json5
@@ -511,12 +511,12 @@
     },
     {
       name: "FullscreenOptions",
-      status: "experimental",
+      status: "stable",
     },
     {
       name: "FullscreenUnprefixed",
       settable_from_internals: true,
-      status: "experimental",
+      status: "stable",
     },
     {
       name: "GamepadButtonAxisEvents",
diff --git a/third_party/blink/renderer/platform/text/character.h b/third_party/blink/renderer/platform/text/character.h
index d451367b..0008f58 100644
--- a/third_party/blink/renderer/platform/text/character.h
+++ b/third_party/blink/renderer/platform/text/character.h
@@ -190,6 +190,18 @@
   // and that script code is not USCRIPT_COMMON or USCRIPT_INHERITED.
   static bool HasDefiniteScript(UChar32);
 
+  static bool IsModernGeorgianUppercase(UChar32 c) {
+    return IsInRange(c, 0x1C90, 0x1CBF);
+  }
+
+  // Map modern secular Georgian uppercase letters added in Unicode
+  // 11.0 to their corresponding lowercase letters.
+  // https://www.unicode.org/charts/PDF/U10A0.pdf
+  // https://www.unicode.org/charts/PDF/U1C90.pdf
+  static UChar32 LowercaseModernGeorgianUppercase(UChar32 c) {
+    return (c - (0x1C90 - 0x10D0));
+  }
+
  private:
   static bool IsCJKIdeographOrSymbolSlow(UChar32);
   static bool IsHangulSlow(UChar32);
diff --git a/third_party/instrumented_libraries/BUILD.gn b/third_party/instrumented_libraries/BUILD.gn
index a2c0f64..114f8ea4 100644
--- a/third_party/instrumented_libraries/BUILD.gn
+++ b/third_party/instrumented_libraries/BUILD.gn
@@ -85,7 +85,7 @@
       "-Wl,-z,origin",
 
       # Add some padding to allow RPATHs to be modified later.
-      "-Wl,-R,________________________________________________________________PADDING________________________________________________________________",
+      "-Wl,-R,________________________________________________________________________________________________PADDING________________________________________________________________________________________________",
     ]
   }
 }
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index ba24bbd..8015b737 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -19943,6 +19943,7 @@
   <int value="2538" label="V8Window_WebkitMediaStream_ConstructorGetter"/>
   <int value="2539" label="TextEncoderStreamConstructor"/>
   <int value="2540" label="TextDecoderStreamConstructor"/>
+  <int value="2541" label="SignedExchangeInnerResponse"/>
 </enum>
 
 <enum name="FeedbackSource">
@@ -51626,6 +51627,8 @@
   <int value="8" label="GET_NODE_VALUE_FAILED"/>
   <int value="9" label="CONVERSION_TO_PROP_VALUE_FAILED"/>
   <int value="10" label="GET_STRING_FAILED"/>
+  <int value="11" label="GET_NAMED_ITEM_NULL"/>
+  <int value="12" label="GET_FIRST_CHILD_NULL"/>
 </enum>
 
 <enum name="WindowsNotificationGetSettingPolicy">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index ec57639..e2453bdb 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -31609,6 +31609,23 @@
   </summary>
 </histogram>
 
+<histogram name="Feed.Offline.GetStatusCount" units="count"
+    expires_after="2019-08-30">
+  <owner>skym@chromium.org</owner>
+  <summary>
+    The number of urls that have offline status requested per call.
+  </summary>
+</histogram>
+
+<histogram name="Feed.Offline.GetStatusDuration" units="ms"
+    expires_after="2019-08-30">
+  <owner>skym@chromium.org</owner>
+  <summary>
+    The number of milliseconds to round trip offline status for a set of URLs
+    from Offline Pages component.
+  </summary>
+</histogram>
+
 <histogram name="Feed.Scheduler.RefreshTrigger" enum="RefreshTrigger"
     expires_after="2019-07-11">
   <owner>skym@chromium.org</owner>
@@ -32414,6 +32431,86 @@
   </summary>
 </histogram>
 
+<histogram name="Gaia.AuthFetcher.ListAccounts.NetErrorCodes"
+    enum="NetErrorCodes" expires_after="2019-08-30">
+  <owner>droger@chromium.org</owner>
+  <owner>msarda@chromium.org</owner>
+  <summary>
+    Reports the network error code for requests to the ListAccounts Gaia
+    endpoint.
+  </summary>
+</histogram>
+
+<histogram name="Gaia.AuthFetcher.ListAccounts.ProcessUptime.Error" units="ms"
+    expires_after="2019-08-30">
+  <owner>droger@chromium.org</owner>
+  <owner>msarda@chromium.org</owner>
+  <summary>
+    Reported when a request to the ListAccounts Gaia endpoint fails to complete
+    for network reasons (i.e. when the error is not OK). This histogram can be
+    used in conjunction with
+    &quot;Gaia.AuthFetcher.ListAccounts.ProcessUptime.Success&quot; in order to
+    compute the failure rate of ListAccounts depending on the process uptime
+    (measured as a base::TimeDelta between the start of the process and the
+    start of the request).
+  </summary>
+</histogram>
+
+<histogram name="Gaia.AuthFetcher.ListAccounts.ProcessUptime.Success"
+    units="ms" expires_after="2019-08-30">
+  <owner>droger@chromium.org</owner>
+  <owner>msarda@chromium.org</owner>
+  <summary>
+    Reported when a request to the ListAccounts Gaia endpoint completes without
+    network error (i.e. when the network error is OK). This histogram can be
+    used in conjunction with
+    &quot;Gaia.AuthFetcher.ListAccounts.ProcessUptime.Error&quot; in order to
+    compute the failure rate of ListAccounts depending on the process uptime
+    (measured as a base::TimeDelta between the start of the process and the
+    start of the request).
+  </summary>
+</histogram>
+
+<histogram name="Gaia.AuthFetcher.ListAccounts.SystemUptime.Error" units="ms"
+    expires_after="2019-08-30">
+  <owner>droger@chromium.org</owner>
+  <owner>msarda@chromium.org</owner>
+  <summary>
+    Reported when a request to the ListAccounts Gaia endpoint fails to complete
+    for network reasons (i.e. when the network error is not OK). This histogram
+    can be used in conjunction with
+    &quot;Gaia.AuthFetcher.ListAccounts.SystemUptime.Success&quot; in order to
+    compute the failure rate of ListAccounts depending on the system uptime
+    (measured as a base::TimeDelta between the start of the system and the start
+    of the request).
+  </summary>
+</histogram>
+
+<histogram name="Gaia.AuthFetcher.ListAccounts.SystemUptime.Success" units="ms"
+    expires_after="2019-08-30">
+  <owner>droger@chromium.org</owner>
+  <owner>msarda@chromium.org</owner>
+  <summary>
+    Reported when a request to the ListAccounts Gaia endpoint completes without
+    network error (i.e. when the network error is OK). This histogram can be
+    used in conjunction with
+    &quot;Gaia.AuthFetcher.ListAccounts.SystemUptime.Error&quot; in order to
+    compute the failure rate of ListAccounts depending on the system uptime
+    (measured as a base::TimeDelta between the start of the system and the start
+    of the request).
+  </summary>
+</histogram>
+
+<histogram name="Gaia.AuthFetcher.Multilogin.AuthErrors"
+    enum="GoogleServiceAuthError" expires_after="2019-08-30">
+  <owner>droger@chromium.org</owner>
+  <owner>msarda@chromium.org</owner>
+  <summary>
+    Return the GoogleAuthError state for each request to the Multilogin Gaia
+    endpoint. NONE is a success, other values are failures.
+  </summary>
+</histogram>
+
 <histogram name="GCM.AndroidGcmReceiverError" enum="GcmReceiverStatus">
   <obsolete>
     Deprecated as of 01/2016. The error has been fixed by GCM. (crbug/580367)
diff --git a/tools/perf/expectations.config b/tools/perf/expectations.config
index d535835..81b2d03 100644
--- a/tools/perf/expectations.config
+++ b/tools/perf/expectations.config
@@ -56,8 +56,10 @@
 crbug.com/867836 [ All ] loading.desktop/Elmundo_warm [ Skip ]
 crbug.com/876636 [ ChromeOS ] loading.desktop/TheOnion_cold [ Skip ]
 crbug.com/876636 [ ChromeOS ] loading.desktop/TheOnion_warm [ Skip ]
+crbug.com/876636 [ Win_10 ] loading.desktop/TheOnion_warm [ Skip ]
 crbug.com/876636 [ ChromeOS ] loading.desktop/AllRecipes_warm [ Skip ]
 crbug.com/879833 [ Mac_10.12 ] loading.desktop/AllRecipes_cold [ Skip ]
+crbug.com/879833 [ Win_10 ] loading.desktop/AllRecipes_cold [ Skip ]
 
 # Benchmark: loading.mobile
 crbug.com/656861 [ All ] loading.mobile/G1 [ Skip ]
diff --git a/ui/android/java/res/values/colors.xml b/ui/android/java/res/values/colors.xml
index ec2793c..f7151659 100644
--- a/ui/android/java/res/values/colors.xml
+++ b/ui/android/java/res/values/colors.xml
@@ -17,6 +17,9 @@
     <color name="default_icon_color_blue" tools:ignore="UnusedResources">
         @color/modern_blue_600
     </color>
+    <color name="default_icon_color_white" tools:ignore="UnusedResources">
+        @android:color/white
+    </color>
 
     <!-- Modern color palette -->
     <color name="modern_blue_300">#8AB4F8</color>
diff --git a/ui/base/ui_features.gni b/ui/base/ui_features.gni
index 2691c6f..5ada6ba6 100644
--- a/ui/base/ui_features.gni
+++ b/ui/base/ui_features.gni
@@ -8,9 +8,6 @@
   # Optional system library.
   use_xkbcommon = false
 
-  # Whether the entire browser uses toolkit-views on Mac instead of Cocoa.
-  mac_views_browser = is_mac
-
   # Whether the platform provides a native accessibility toolkit.
   has_native_accessibility = use_atk || is_win || is_mac
 
@@ -22,3 +19,8 @@
 }
 
 enable_hidpi = is_mac || is_win || is_linux
+
+# Whether the entire browser uses toolkit-views on Mac instead of Cocoa.
+# TODO(https://crbug.com/832676): Now that this is always true, remove all uses
+# of this and then remove it.
+mac_views_browser = is_mac
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager.js b/ui/file_manager/file_manager/foreground/js/file_manager.js
index f5f03d1..63e14f4 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager.js
@@ -1231,9 +1231,12 @@
                 isDirectory: true,
                 rootType: VolumeManagerCommon.RootType.CROSTINI,
                 name: str('LINUX_FILES_ROOT_LABEL'),
-                toURL: function() {
+                toURL: () => {
                   return 'fake-entry://linux-files';
                 },
+                getMetadata: (onSuccess) => {
+                  onSuccess({});
+                },
                 iconName: VolumeManagerCommon.VolumeType.CROSTINI,
               }) :
           null;
diff --git a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
index 4635f5c..78bb289 100644
--- a/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
+++ b/ui/file_manager/file_manager/foreground/js/file_manager_commands.js
@@ -1644,7 +1644,8 @@
 
 
 /**
- * Shares the selected (single only) folder with crostini container.
+ * Shares the selected (single only) Downloads subfolder with crostini
+ * container.
  * @type {Command}
  */
 CommandHandler.COMMANDS_['share-with-linux'] = /** @type {Command} */ ({
@@ -1669,9 +1670,13 @@
    * @param {!CommandHandlerDeps} fileManager CommandHandlerDeps to use.
    */
   canExecute: function(event, fileManager) {
+    // Must be single directory subfolder of Downloads.
     const entries = CommandUtil.getCommandEntries(event.target);
     event.canExecute = CommandHandler.IS_CROSTINI_FILES_ENABLED_ &&
-        entries.length === 1 && entries[0].isDirectory;
+        entries.length === 1 && entries[0].isDirectory &&
+        entries[0].fullPath !== '/' &&
+        fileManager.volumeManager.getLocationInfo(entries[0]).rootType ===
+            VolumeManagerCommon.RootType.DOWNLOADS;
     event.command.setHidden(!event.canExecute);
   }
 });
diff --git a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider.js b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider.js
index 4f3f0ca..18135e9 100644
--- a/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider.js
+++ b/ui/file_manager/file_manager/foreground/js/metadata/file_system_metadata_provider.js
@@ -42,7 +42,7 @@
       // Can't use console.error because some tests hit this line and
       // console.error causes them to fail because of JSErrorCount. This error
       // is an acceptable condition.
-      console.warn('getMetadata failure for: ' + request.entry.fullPath, error);
+      console.warn('getMetadata failure for: ' + request.entry.toURL(), error);
       return new MetadataItem();
     });
   }));
diff --git a/ui/file_manager/file_manager/test/crostini.js b/ui/file_manager/file_manager/test/crostini.js
index bd97730d..603689ab 100644
--- a/ui/file_manager/file_manager/test/crostini.js
+++ b/ui/file_manager/file_manager/test/crostini.js
@@ -226,3 +226,72 @@
         done();
       });
 };
+
+// Verify right-click menu with 'Share with Linux' is not shown for:
+// * Root Downloads folder
+// * Any folder outside of downloads (e.g. crostini or drive)
+crostini.testSharePathNotShown = (done) => {
+  const myFiles = '#directory-tree .tree-item [root-type-icon="my_files"]';
+  const downloads = '#file-list li [file-type-icon="downloads"]';
+  const linuxFiles = '#directory-tree .tree-item [root-type-icon="crostini"]';
+  const googleDrive = '#directory-tree .tree-item [volume-type-icon="drive"]';
+  const menuNoShareWithLinux = '#file-context-menu:not([hidden]) ' +
+      '[command="#share-with-linux"][hidden][disabled="disabled"]';
+
+  test.setupAndWaitUntilReady()
+      .then(() => {
+        // Select 'My files' in directory tree to show Downloads in file list.
+        assertTrue(test.fakeMouseClick(myFiles), 'click My files');
+        return test.waitForElement(downloads);
+      })
+      .then(() => {
+        // Right-click 'Downloads' directory.
+        // Check 'Share with Linux' is not shown in menu.
+        assertTrue(
+            test.fakeMouseRightClick(downloads), 'right-click downloads');
+        return test.waitForElement(menuNoShareWithLinux);
+      })
+      .then(() => {
+        // Select 'Linux files' in directory tree to show dir A in file list.
+        return test.waitForElement(linuxFiles);
+      })
+      .then(() => {
+        assertTrue(test.fakeMouseClick(linuxFiles), 'click Linux files');
+        return test.waitForFiles(
+            test.TestEntryInfo.getExpectedRows(test.BASIC_CROSTINI_ENTRY_SET));
+      })
+      .then(() => {
+        // Check 'Share with Linux' is not shown in menu.
+        test.selectFile('A');
+        assertTrue(
+            test.fakeMouseRightClick('#file-list li[selected]'),
+            'right-click directory A');
+        return test.waitForElement(menuNoShareWithLinux);
+      })
+      .then(() => {
+        // Select 'Google Drive' to show dir photos in file list.
+        return test.waitForElement(googleDrive);
+      })
+      .then(() => {
+        assertTrue(test.fakeMouseClick(googleDrive), 'click Google Drive');
+        return test.waitForFiles(
+            test.TestEntryInfo.getExpectedRows(test.BASIC_DRIVE_ENTRY_SET));
+      })
+      .then(() => {
+        // Check 'Share with Linux' is not shown in menu.
+        test.selectFile('photos');
+        assertTrue(
+            test.fakeMouseRightClick('#file-list li[selected]'),
+            'right-click photos');
+        return test.waitForElement(menuNoShareWithLinux);
+      })
+      .then(() => {
+        // Reset Linux files back to unmounted.
+        chrome.fileManagerPrivate.removeMount('crostini');
+        return test.waitForElement(
+            '#directory-tree .tree-item [root-type-icon="crostini"]');
+      })
+      .then(() => {
+        done();
+      });
+};
diff --git a/ui/file_manager/file_manager/test/js/chrome_file_manager_private_test_impl.js b/ui/file_manager/file_manager/test/js/chrome_file_manager_private_test_impl.js
index cc3aa9e3..f6737b3 100644
--- a/ui/file_manager/file_manager/test/js/chrome_file_manager_private_test_impl.js
+++ b/ui/file_manager/file_manager/test/js/chrome_file_manager_private_test_impl.js
@@ -79,7 +79,7 @@
     // Returns chrome.fileManagerPrivate.FileTask[].
     var results = [];
     // Support for view-in-browser on single text file used by QuickView.
-    if (entries.length == 1 &&
+    if (entries.length == 1 && entries[0].metadata &&
         entries[0].metadata.contentMimeType == 'text/plain') {
       results.push({
         taskId: 'hhaomjibdihmijegdhdafkllkbggdgoj|file|view-in-browser',
diff --git a/ui/file_manager/file_manager/test/js/strings.js b/ui/file_manager/file_manager/test/js/strings.js
index f4b165c..2942bbd6 100644
--- a/ui/file_manager/file_manager/test/js/strings.js
+++ b/ui/file_manager/file_manager/test/js/strings.js
@@ -57,6 +57,7 @@
       GOOGLE_DRIVE_REDEEM_URL: 'http://www.google.com/intl/en/chrome/' +
           'devices/goodies.html?utm_source=filesapp&utm_medium=banner&' +
           'utm_campaign=gsg',
+      HIDE_SPACE_INFO: false,
       IMAGE_FILE_TYPE: '$1 image',
       INSTALL_LINUX_PACKAGE_INSTALL_BUTTON: 'Install',
       INSTALL_NEW_EXTENSION_LABEL: 'Install new service',
diff --git a/ui/file_manager/file_manager/test/js/test_util.js b/ui/file_manager/file_manager/test/js/test_util.js
index 2f0f32f..572f80e 100644
--- a/ui/file_manager/file_manager/test/js/test_util.js
+++ b/ui/file_manager/file_manager/test/js/test_util.js
@@ -279,6 +279,7 @@
  * @const
  */
 test.BASIC_CROSTINI_ENTRY_SET = [
+  test.ENTRIES.directoryA,
   test.ENTRIES.hello,
   test.ENTRIES.world,
   test.ENTRIES.desktop,
diff --git a/ui/views/accessibility/ax_aura_obj_cache.cc b/ui/views/accessibility/ax_aura_obj_cache.cc
index 519d09c..9fffbd6 100644
--- a/ui/views/accessibility/ax_aura_obj_cache.cc
+++ b/ui/views/accessibility/ax_aura_obj_cache.cc
@@ -31,6 +31,8 @@
 }
 
 AXAuraObjWrapper* AXAuraObjCache::GetOrCreate(View* view) {
+  if (!view->GetWidget())
+    return nullptr;
   return CreateInternal<AXViewObjWrapper>(view, view_to_id_map_);
 }
 
@@ -122,24 +124,28 @@
 }
 
 View* AXAuraObjCache::GetFocusedView() {
-  if (root_windows_.empty())
-    return nullptr;
-  aura::client::FocusClient* focus_client =
-      GetFocusClient(*root_windows_.begin());
-  if (!focus_client)
-    return nullptr;
+  Widget* focused_widget = focused_widget_for_testing_;
+  aura::Window* focused_window = nullptr;
+  if (!focused_widget) {
+    if (root_windows_.empty())
+      return nullptr;
+    aura::client::FocusClient* focus_client =
+        GetFocusClient(*root_windows_.begin());
+    if (!focus_client)
+      return nullptr;
 
-  aura::Window* focused_window = focus_client->GetFocusedWindow();
-  if (!focused_window)
-    return nullptr;
-
-  Widget* focused_widget = Widget::GetWidgetForNativeView(focused_window);
-  while (!focused_widget) {
-    focused_window = focused_window->parent();
+    focused_window = focus_client->GetFocusedWindow();
     if (!focused_window)
-      break;
+      return nullptr;
 
     focused_widget = Widget::GetWidgetForNativeView(focused_window);
+    while (!focused_widget) {
+      focused_window = focused_window->parent();
+      if (!focused_window)
+        break;
+
+      focused_widget = Widget::GetWidgetForNativeView(focused_window);
+    }
   }
 
   if (!focused_widget)
@@ -153,7 +159,8 @@
   if (focused_view)
     return focused_view;
 
-  if (focused_window->GetProperty(
+  if (focused_window &&
+      focused_window->GetProperty(
           aura::client::kAccessibilityFocusFallsbackToWidgetKey)) {
     // If focused widget has non client view, falls back to first child view of
     // its client view. We don't expect that non client view gets keyboard
diff --git a/ui/views/accessibility/ax_aura_obj_cache.h b/ui/views/accessibility/ax_aura_obj_cache.h
index f798bdb..83f3155 100644
--- a/ui/views/accessibility/ax_aura_obj_cache.h
+++ b/ui/views/accessibility/ax_aura_obj_cache.h
@@ -92,6 +92,13 @@
 
   void SetDelegate(Delegate* delegate) { delegate_ = delegate; }
 
+  // Changes the behavior of GetFocusedView() so that it only considers
+  // views within the given Widget, this enables making tests
+  // involving focus reliable.
+  void set_focused_widget_for_testing(views::Widget* widget) {
+    focused_widget_for_testing_ = widget;
+  }
+
  private:
   friend struct base::DefaultSingletonTraits<AXAuraObjCache>;
 
@@ -131,6 +138,8 @@
 
   std::set<aura::Window*> root_windows_;
 
+  views::Widget* focused_widget_for_testing_ = nullptr;
+
   DISALLOW_COPY_AND_ASSIGN(AXAuraObjCache);
 };
 
diff --git a/ui/views/cocoa/bridged_native_widget.mm b/ui/views/cocoa/bridged_native_widget.mm
index 881dcc2..a15a32c 100644
--- a/ui/views/cocoa/bridged_native_widget.mm
+++ b/ui/views/cocoa/bridged_native_widget.mm
@@ -609,7 +609,8 @@
 Widget::MoveLoopResult BridgedNativeWidgetImpl::RunMoveLoop(
     const gfx::Vector2d& drag_offset) {
   DCHECK(!HasCapture());
-  DCHECK(!window_move_loop_);
+  // https://crbug.com/876493
+  CHECK(!window_move_loop_);
 
   // RunMoveLoop caller is responsible for updating the window to be under the
   // mouse, but it does this using possibly outdated coordinate from the mouse
diff --git a/ui/views/cocoa/cocoa_window_move_loop.mm b/ui/views/cocoa/cocoa_window_move_loop.mm
index a7f21dc..fb2e375152 100644
--- a/ui/views/cocoa/cocoa_window_move_loop.mm
+++ b/ui/views/cocoa/cocoa_window_move_loop.mm
@@ -4,7 +4,10 @@
 
 #include "ui/views/cocoa/cocoa_window_move_loop.h"
 
+#include "base/debug/stack_trace.h"
 #include "base/run_loop.h"
+#include "base/strings/stringprintf.h"
+#include "components/crash/core/common/crash_key.h"
 #include "ui/display/screen.h"
 #import "ui/gfx/mac/coordinate_conversion.h"
 #import "ui/views/cocoa/bridged_native_widget.h"
@@ -46,6 +49,13 @@
       weak_factory_(this) {}
 
 CocoaWindowMoveLoop::~CocoaWindowMoveLoop() {
+  // Record the address and stack to help catch https://crbug.com/876493.
+  static crash_reporter::CrashKeyString<19> address_key("move_loop_address");
+  address_key.Set(base::StringPrintf("%p", this));
+
+  static crash_reporter::CrashKeyString<1024> stack_key("move_loop_stack");
+  crash_reporter::SetCrashKeyStringToStackTrace(&stack_key,
+                                                base::debug::StackTrace());
   // Handle the pathological case, where |this| is destroyed while running.
   if (exit_reason_ref_) {
     *exit_reason_ref_ = WINDOW_DESTROYED;
@@ -73,6 +83,10 @@
   // TabDragController.
   NSEventMask mask = NSLeftMouseUpMask | NSLeftMouseDraggedMask;
   auto handler = ^NSEvent*(NSEvent* event) {
+    // The docs say this always runs on the main thread, but if it didn't,
+    // it would explain https://crbug.com/876493, so let's make sure.
+    CHECK_EQ(CFRunLoopGetMain(), CFRunLoopGetCurrent());
+
     CocoaWindowMoveLoop* strong = [weak_cocoa_window_move_loop weak].get();
     if (!strong || !strong->exit_reason_ref_) {
       // By this point CocoaWindowMoveLoop was deleted while processing this
diff --git a/ui/views/mus/ax_remote_host_unittest.cc b/ui/views/mus/ax_remote_host_unittest.cc
index fd18735..24116ed 100644
--- a/ui/views/mus/ax_remote_host_unittest.cc
+++ b/ui/views/mus/ax_remote_host_unittest.cc
@@ -165,18 +165,6 @@
   EXPECT_EQ(ax::mojom::Event::kLoadComplete, service.last_event_.event_type);
 }
 
-// Views can trigger accessibility events during Widget construction before the
-// AXRemoteHost starts monitoring the widget. This happens with the material
-// design focus ring on text fields. Verify we don't crash in this case.
-// https://crbug.com/862759
-TEST_F(AXRemoteHostTest, SendEventBeforeWidgetCreated) {
-  TestAXHostService service(true /*automation_enabled*/);
-  AXRemoteHost* remote = CreateRemote(&service);
-  views::View view;
-  remote->HandleEvent(&view, ax::mojom::Event::kLocationChanged);
-  // No crash.
-}
-
 // Verifies that the AXRemoteHost stops monitoring widgets that are closed
 // asynchronously, like when ash requests close via DesktopWindowTreeHostMus.
 // https://crbug.com/869608
@@ -230,6 +218,9 @@
 
   // Create a view to sense the action.
   TestView view;
+  view.SetBounds(0, 0, 100, 100);
+  std::unique_ptr<Widget> widget = CreateTestWidget();
+  widget->GetRootView()->AddChildView(&view);
   AXAuraObjCache::GetInstance()->GetOrCreate(&view);
 
   // Request an action on the view.
diff --git a/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.html b/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.html
index f28f89b..9e3c4b2 100644
--- a/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.html
+++ b/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.html
@@ -160,7 +160,7 @@
             is-input-rtl$="[[isInputRtl_(value)]]"
             has-content$="[[hasInput_(value)]]" invalid="[[hasError]]"
             placeholder="[[getInputPlaceholder_(enablePassword)]]"
-            on-keydown="onInputKeyDown_">
+            on-keydown="onInputKeyDown_" force-underline$="[[forceUnderline_]]">
         </cr-input>
       </div>
       <slot select="[problem]"></slot>
diff --git a/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.js b/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.js
index 0f7e3da6..dda4a1e 100644
--- a/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.js
+++ b/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.js
@@ -103,6 +103,19 @@
       value: '',
       observer: 'onPinValueChange_',
     },
+
+    /**
+     * @private
+     */
+    forceUnderline_: {
+      type: Boolean,
+      value: false,
+    }
+  },
+
+  listeners: {
+    'blur': 'onBlur_',
+    'focus': 'onFocus_',
   },
 
   /**
@@ -174,6 +187,16 @@
     this.focus(this.selectionStart_, this.selectionEnd_);
   },
 
+  /** @private */
+  onFocus_: function() {
+    this.forceUnderline_ = true;
+  },
+
+  /** @private */
+  onBlur_: function() {
+    this.forceUnderline_ = false;
+  },
+
   /**
    * Called when a keypad number has been tapped.
    * @param {Event} event The event object.
diff --git a/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html b/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html
index 2b3e104..578e5971 100644
--- a/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html
+++ b/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html
@@ -78,11 +78,12 @@
         opacity: 0;
         position: absolute;
         right: 0;
-        transition: opacity 120ms ease-out, width 0 linear 180ms;
+        transition: opacity 120ms ease-out, width 0s linear 180ms;
         width: 0;
       }
 
       :host([invalid]) #underline,
+      :host([force-underline]) #underline,
       :host([focused_]:not([readonly])) #underline {
         opacity: 1;
         transition: width 180ms ease-out, opacity 120ms ease-in;