diff --git a/DEPS b/DEPS
index 08794874..b7fe5c7e 100644
--- a/DEPS
+++ b/DEPS
@@ -167,11 +167,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': '3787f51c65c33eda4a5f81e16b5e7e2d01f93943',
+  'skia_revision': 'dca6b5fe9a3243c3ca646a7d9fd2c5c23a3291b9',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': 'd033cf119f93f2fe742ea7970d3394a060cffb3c',
+  'v8_revision': 'b1db47127366167e720281589d2951b16c2bd97b',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
@@ -230,7 +230,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling catapult
   # and whatever else without interference from each other.
-  'catapult_revision': '15152b52a721da1352f8f9fedcd4dd0c4a2f6cac',
+  'catapult_revision': 'ed74a5890e50e44f88799ed788bb0fbf46b2cfe0',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
@@ -246,7 +246,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.
-  'feed_revision': 'c25c8f41145ed610d1a73004e8bcd62d8e8111c1',
+  'feed_revision': '78a886b204af52d24e298852587fc99f68cee626',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling android_sdk_build-tools_version
   # and whatever else without interference from each other.
@@ -302,11 +302,11 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'dawn_revision': '86ac0b93c9afc7682c9e31f573dd387dc601dfbf',
+  'dawn_revision': 'f622a447500234810f3eb3aafff6358d7cff6628',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling feed
   # and whatever else without interference from each other.
-  'quiche_revision': 'f0fe2069005c907660534fc7d3ee9694c79799d6',
+  'quiche_revision': 'd85976f86ec30f805add4c0603900854800989ff',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling ios_webkit
   # and whatever else without interference from each other.
@@ -862,7 +862,7 @@
 
   # Build tools for Chrome OS. Note: This depends on third_party/pyelftools.
   'src/third_party/chromite': {
-      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'a2aeb375f63ca0734f3eb63d9256b50221c1d920',
+      'url': Var('chromium_git') + '/chromiumos/chromite.git' + '@' + 'b04334392d997af0a0aae652e4394d73857fd34c',
       'condition': 'checkout_linux',
   },
 
@@ -887,7 +887,7 @@
   },
 
   'src/third_party/depot_tools':
-    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '2b829368295598cb663f9e7b931c330d5697cfc3',
+    Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '69d781151b8a374bd7bb42730dd0e5f6331604ba',
 
   'src/third_party/devtools-node-modules':
     Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'),
@@ -1269,7 +1269,7 @@
   },
 
   'src/third_party/perfetto':
-    Var('android_git') + '/platform/external/perfetto.git' + '@' + '7505235b577c4f720c439ae33f409d0563e13360',
+    Var('android_git') + '/platform/external/perfetto.git' + '@' + 'f96bdd640172f1cc2b7e505fd883e2caea25c919',
 
   'src/third_party/perl': {
       'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + '6f3e5028eb65d0b4c5fdd792106ac4c84eee1eb3',
@@ -1521,7 +1521,7 @@
     Var('chromium_git') + '/v8/v8.git' + '@' +  Var('v8_revision'),
 
   'src-internal': {
-    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@b2ed47b33935fb53bf38bf1af020f9dfbf7666be',
+    'url': 'https://chrome-internal.googlesource.com/chrome/src-internal.git@4400cb93e9b9381b4995cad49738499c921d9f36',
     'condition': 'checkout_src_internal',
   },
 
diff --git a/android_webview/browser/aw_metrics_service_client.cc b/android_webview/browser/aw_metrics_service_client.cc
index 6c835e7..cd180b5 100644
--- a/android_webview/browser/aw_metrics_service_client.cc
+++ b/android_webview/browser/aw_metrics_service_client.cc
@@ -19,6 +19,7 @@
 #include "base/lazy_instance.h"
 #include "base/strings/string16.h"
 #include "components/metrics/call_stack_profile_metrics_provider.h"
+#include "components/metrics/cpu_metrics_provider.h"
 #include "components/metrics/enabled_state_provider.h"
 #include "components/metrics/gpu/gpu_metrics_provider.h"
 #include "components/metrics/metrics_log_uploader.h"
@@ -108,6 +109,8 @@
       std::make_unique<metrics::NetworkMetricsProvider>(
           content::CreateNetworkConnectionTrackerAsyncGetter()));
   service->RegisterMetricsProvider(
+      std::make_unique<metrics::CPUMetricsProvider>());
+  service->RegisterMetricsProvider(
       std::make_unique<metrics::GPUMetricsProvider>());
   service->RegisterMetricsProvider(
       std::make_unique<metrics::ScreenInfoMetricsProvider>());
diff --git a/android_webview/browser/network_service/android_stream_reader_url_loader_unittest.cc b/android_webview/browser/network_service/android_stream_reader_url_loader_unittest.cc
index e094914..ab66791a 100644
--- a/android_webview/browser/network_service/android_stream_reader_url_loader_unittest.cc
+++ b/android_webview/browser/network_service/android_stream_reader_url_loader_unittest.cc
@@ -248,8 +248,8 @@
   client->RunUntilComplete();
   EXPECT_EQ(net::OK, client->completion_status().error_code);
   EXPECT_EQ("HTTP/1.1 200 OK",
-            client->response_head().headers->GetStatusLine());
-  VerifyHeaderNameAndValue(client->response_head().headers.get(), "Client-Via",
+            client->response_head()->headers->GetStatusLine());
+  VerifyHeaderNameAndValue(client->response_head()->headers.get(), "Client-Via",
                            "shouldInterceptRequest");
 }
 
@@ -276,7 +276,7 @@
   client->RunUntilComplete();
   EXPECT_EQ(net::OK, client->completion_status().error_code);
   EXPECT_EQ("HTTP/1.1 200 OK",
-            client->response_head().headers->GetStatusLine());
+            client->response_head()->headers->GetStatusLine());
 }
 
 TEST_F(AndroidStreamReaderURLLoaderTest, InvalidRangeRequest) {
@@ -304,8 +304,8 @@
   client->RunUntilComplete();
   EXPECT_EQ(net::OK, client->completion_status().error_code);
   EXPECT_EQ("HTTP/1.1 404 Not Found",
-            client->response_head().headers->GetStatusLine());
-  VerifyHeaderNameAndValue(client->response_head().headers.get(), "Client-Via",
+            client->response_head()->headers->GetStatusLine());
+  VerifyHeaderNameAndValue(client->response_head()->headers.get(), "Client-Via",
                            "shouldInterceptRequest");
 }
 
@@ -321,8 +321,8 @@
   client->RunUntilComplete();
   EXPECT_EQ(net::OK, client->completion_status().error_code);
   EXPECT_EQ("HTTP/1.1 200 OK",
-            client->response_head().headers->GetStatusLine());
-  VerifyHeaderNameAndValue(client->response_head().headers.get(), "Client-Via",
+            client->response_head()->headers->GetStatusLine());
+  VerifyHeaderNameAndValue(client->response_head()->headers.get(), "Client-Via",
                            "shouldInterceptRequest");
   std::string body = ReadAvailableBody(client.get());
   EXPECT_EQ(expected_body, body);
@@ -341,7 +341,7 @@
   client->RunUntilComplete();
   EXPECT_EQ(net::OK, client->completion_status().error_code);
   EXPECT_EQ("HTTP/1.1 200 OK",
-            client->response_head().headers->GetStatusLine());
+            client->response_head()->headers->GetStatusLine());
   std::string body = ReadAvailableBody(client.get());
   EXPECT_EQ(expected_body + expected_body, body);
 }
@@ -364,7 +364,7 @@
   EXPECT_TRUE(client->has_received_response());
   EXPECT_FALSE(client->has_received_completion());
   EXPECT_EQ("HTTP/1.1 200 OK",
-            client->response_head().headers->GetStatusLine());
+            client->response_head()->headers->GetStatusLine());
   auto response_body = client->response_body_release();
   response_body.reset();
   client->RunUntilComplete();
@@ -389,10 +389,10 @@
   client->RunUntilComplete();
   EXPECT_EQ(net::OK, client->completion_status().error_code);
   EXPECT_EQ(custom_status_line,
-            client->response_head().headers->GetStatusLine());
-  VerifyHeaderNameAndValue(client->response_head().headers.get(),
+            client->response_head()->headers->GetStatusLine());
+  VerifyHeaderNameAndValue(client->response_head()->headers.get(),
                            custom_header_name, custom_header_value);
-  VerifyHeaderNameAndValue(client->response_head().headers.get(), "Client-Via",
+  VerifyHeaderNameAndValue(client->response_head()->headers.get(), "Client-Via",
                            "shouldInterceptRequest");
 }
 
diff --git a/android_webview/docs/navbar.md b/android_webview/docs/navbar.md
index 71b80fe..3ce9f7e 100644
--- a/android_webview/docs/navbar.md
+++ b/android_webview/docs/navbar.md
@@ -12,6 +12,8 @@
 * [FAQ (for users)](/android_webview/docs/faq.md)
 * [AOSP system integration](/android_webview/docs/aosp-system-integration.md)
 * [Threading](/android_webview/docs/threading.md)
+  <!-- Link new docs above this line. -->
+* [More docs](/android_webview/docs/)
 
 [home]: /android_webview/docs/README.md
 [logo]: /android_webview/docs/images/webview_logo.png
diff --git a/ash/BUILD.gn b/ash/BUILD.gn
index ce514a4..046a436 100644
--- a/ash/BUILD.gn
+++ b/ash/BUILD.gn
@@ -1217,6 +1217,7 @@
     "wm/splitview/split_view_drag_indicators.h",
     "wm/splitview/split_view_highlight_view.cc",
     "wm/splitview/split_view_highlight_view.h",
+    "wm/splitview/split_view_observer.h",
     "wm/splitview/split_view_test_api.cc",
     "wm/splitview/split_view_utils.cc",
     "wm/splitview/split_view_utils.h",
diff --git a/ash/app_list/app_list_controller_impl_unittest.cc b/ash/app_list/app_list_controller_impl_unittest.cc
index 5696b99..d374a2d 100644
--- a/ash/app_list/app_list_controller_impl_unittest.cc
+++ b/ash/app_list/app_list_controller_impl_unittest.cc
@@ -276,6 +276,46 @@
             GetAppListViewNativeWindow()->bounds());
 }
 
+// Verifies that in clamshell mode the AppListView bounds remain in the
+// fullscreen size while the virtual keyboard is shown, even if the app list
+// view state changes.
+TEST_F(AppListControllerImplTest,
+       AppListViewBoundsRemainFullScreenWhenVKeyboardEnabled) {
+  Shell::Get()->keyboard_controller()->SetEnableFlag(
+      keyboard::KeyboardEnableFlag::kShelfEnabled);
+
+  // Show the AppListView in fullscreen state and click on the search box with
+  // the mouse. So the VirtualKeyboard is shown. Wait until the virtual keyboard
+  // shows.
+  ShowAppListNow();
+  GetSearchBoxView()->SetSearchBoxActive(true, ui::ET_MOUSE_PRESSED);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(ash::AppListViewState::kHalf, GetAppListView()->app_list_state());
+  EXPECT_TRUE(GetVirtualKeyboardWindow()->IsVisible());
+
+  EXPECT_EQ(0, GetAppListView()->GetBoundsInScreen().y());
+
+  // Simulate half state getting set again, and but verify the app list bounds
+  // remain at the top of the screen.
+  GetAppListView()->SetState(AppListViewState::kHalf);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(ash::AppListViewState::kHalf, GetAppListView()->app_list_state());
+
+  EXPECT_EQ(0, GetAppListView()->GetBoundsInScreen().y());
+
+  // Close the virtual keyboard. Wait until it is hidden.
+  Shell::Get()->keyboard_controller()->HideKeyboard(HideReason::kUser);
+  base::RunLoop().RunUntilIdle();
+  EXPECT_EQ(nullptr, GetVirtualKeyboardWindow());
+
+  // Verify the app list bounds have been updated to match kHalf state.
+  EXPECT_EQ(ash::AppListViewState::kHalf, GetAppListView()->app_list_state());
+  const gfx::Rect shelf_bounds =
+      AshTestBase::GetPrimaryShelf()->shelf_widget()->GetWindowBoundsInScreen();
+  EXPECT_EQ(shelf_bounds.bottom() - 545 /*half app list height*/,
+            GetAppListView()->GetBoundsInScreen().y());
+}
+
 // Verifies that in tablet mode, the AppListView has correct bounds when the
 // virtual keyboard is dismissed (see https://crbug.com/944133).
 TEST_F(AppListControllerImplTest, CheckAppListViewBoundsWhenDismissVKeyboard) {
diff --git a/ash/app_list/app_list_presenter_delegate_unittest.cc b/ash/app_list/app_list_presenter_delegate_unittest.cc
index 32b9a403..0f21835 100644
--- a/ash/app_list/app_list_presenter_delegate_unittest.cc
+++ b/ash/app_list/app_list_presenter_delegate_unittest.cc
@@ -1451,6 +1451,51 @@
   GetAppListTestHelper()->CheckVisibility(false);
 }
 
+// Tests that drag using a mouse does not always close the app list if the app
+// list was previously closed using a fling gesture.
+TEST_P(AppListPresenterDelegateTest, MouseDragAfterDownwardFliing) {
+  const bool test_fullscreen = GetParam();
+  GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
+
+  app_list::AppListView* view = GetAppListView();
+  const gfx::Point expand_arrow_point = view->app_list_main_view()
+                                            ->contents_view()
+                                            ->expand_arrow_view()
+                                            ->GetBoundsInScreen()
+                                            .CenterPoint();
+
+  if (test_fullscreen)
+    GetEventGenerator()->GestureTapAt(expand_arrow_point);
+  GetAppListTestHelper()->CheckState(test_fullscreen
+                                         ? AppListViewState::kFullscreenAllApps
+                                         : AppListViewState::kPeeking);
+
+  // Fling down, the app list should close.
+  FlingUpOrDown(GetEventGenerator(), view, false /* down */);
+  GetAppListTestHelper()->WaitUntilIdle();
+  GetAppListTestHelper()->CheckState(AppListViewState::kClosed);
+
+  // Show the app list again, and perform mouse drag that ends up at the same
+  // position.
+  GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
+  if (test_fullscreen)
+    GetEventGenerator()->GestureTapAt(expand_arrow_point);
+  GetAppListTestHelper()->CheckState(test_fullscreen
+                                         ? AppListViewState::kFullscreenAllApps
+                                         : AppListViewState::kPeeking);
+
+  GetEventGenerator()->MoveMouseTo(GetPointOutsideSearchbox());
+  GetEventGenerator()->PressLeftButton();
+  GetEventGenerator()->MoveMouseBy(0, -10);
+  GetEventGenerator()->MoveMouseBy(0, 10);
+  GetEventGenerator()->ReleaseLeftButton();
+
+  // Verify the app list state has not changed.
+  GetAppListTestHelper()->CheckState(test_fullscreen
+                                         ? AppListViewState::kFullscreenAllApps
+                                         : AppListViewState::kPeeking);
+}
+
 TEST_F(AppListPresenterDelegateTest,
        MouseWheelFromAppListPresenterImplTransitionsAppListState) {
   GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId());
diff --git a/ash/app_list/views/app_list_view.cc b/ash/app_list/views/app_list_view.cc
index d14173f9..9fd9d26 100644
--- a/ash/app_list/views/app_list_view.cc
+++ b/ash/app_list/views/app_list_view.cc
@@ -932,16 +932,18 @@
     return;
   }
 
+  // Remember the last fling velocity, as the value gets reset in SetIsInDrag.
+  const int last_fling_velocity = last_fling_velocity_;
   SetIsInDrag(false);
 
   // Change the app list state based on where the drag ended. If fling velocity
   // was over the threshold, snap to the next state in the direction of the
   // fling.
-  if (std::abs(last_fling_velocity_) >= kDragVelocityThreshold) {
+  if (std::abs(last_fling_velocity) >= kDragVelocityThreshold) {
     // If the user releases drag with velocity over the threshold, snap to
     // the next state, ignoring the drag release position.
 
-    if (last_fling_velocity_ > 0) {
+    if (last_fling_velocity > 0) {
       switch (app_list_state_) {
         case ash::AppListViewState::kPeeking:
         case ash::AppListViewState::kHalf:
@@ -1785,6 +1787,10 @@
   if (is_in_drag == is_in_drag_)
     return;
 
+  // Reset |last_fling_velocity_| if it was set during the drag.
+  if (!is_in_drag)
+    last_fling_velocity_ = 0;
+
   // Don't allow dragging to interrupt the close animation, it probably is not
   // intentional.
   if (app_list_state_ == ash::AppListViewState::kClosed)
@@ -2191,6 +2197,17 @@
   // container's y as the top of display.
   const display::Display display = GetDisplayNearestView();
   const gfx::Rect work_area_bounds = display.work_area();
+
+  // The ChromeVox panel as well as the Docked Magnifier viewport affect the
+  // workarea of the display. We need to account for that when applist is in
+  // fullscreen to avoid being shown below them.
+  const int fullscreen_height = work_area_bounds.y() - display.bounds().y();
+
+  // Force fullscreen height if onscreen keyboard is shown to match the UI state
+  // that's set by default when the onscreen keyboard is first shown.
+  if (onscreen_keyboard_shown_ && state != ash::AppListViewState::kClosed)
+    return fullscreen_height;
+
   switch (state) {
     case ash::AppListViewState::kPeeking:
       return display.bounds().height() -
@@ -2200,10 +2217,7 @@
                       display.bounds().height() - kHalfAppListHeight);
     case ash::AppListViewState::kFullscreenAllApps:
     case ash::AppListViewState::kFullscreenSearch:
-      // The ChromeVox panel as well as the Docked Magnifier viewport affect the
-      // workarea of the display. We need to account for that when applist is in
-      // fullscreen to avoid being shown below them.
-      return work_area_bounds.y() - display.bounds().y();
+      return fullscreen_height;
     case ash::AppListViewState::kClosed:
       // Align the widget y with shelf y to avoid flicker in show animation. In
       // side shelf mode, the widget y is the top of work area because the
diff --git a/ash/display/screen_orientation_controller.cc b/ash/display/screen_orientation_controller.cc
index 07d77f6..76d56ada1 100644
--- a/ash/display/screen_orientation_controller.cc
+++ b/ash/display/screen_orientation_controller.cc
@@ -417,10 +417,10 @@
 }
 
 void ScreenOrientationController::OnSplitViewStateChanged(
-    SplitViewState previous_state,
-    SplitViewState state) {
-  if (previous_state == SplitViewState::kNoSnap ||
-      state == SplitViewState::kNoSnap) {
+    SplitViewController::State previous_state,
+    SplitViewController::State state) {
+  if (previous_state == SplitViewController::State::kNoSnap ||
+      state == SplitViewController::State::kNoSnap) {
     ApplyLockForActiveWindow();
   }
 }
diff --git a/ash/display/screen_orientation_controller.h b/ash/display/screen_orientation_controller.h
index c9146d1..9396480 100644
--- a/ash/display/screen_orientation_controller.h
+++ b/ash/display/screen_orientation_controller.h
@@ -12,8 +12,9 @@
 #include "ash/ash_export.h"
 #include "ash/display/display_configuration_controller.h"
 #include "ash/display/window_tree_host_manager.h"
-#include "ash/public/cpp/split_view.h"
 #include "ash/public/cpp/tablet_mode_observer.h"
+#include "ash/wm/splitview/split_view_controller.h"
+#include "ash/wm/splitview/split_view_observer.h"
 #include "base/macros.h"
 #include "base/observer_list.h"
 #include "ui/aura/window_observer.h"
@@ -155,8 +156,8 @@
   void OnTabletModeEnded() override;
 
   // SplitViewObserver:
-  void OnSplitViewStateChanged(SplitViewState previous_state,
-                               SplitViewState state) override;
+  void OnSplitViewStateChanged(SplitViewController::State previous_state,
+                               SplitViewController::State state) override;
 
  private:
   friend class ScreenOrientationControllerTestApi;
diff --git a/ash/frame/non_client_frame_view_ash.h b/ash/frame/non_client_frame_view_ash.h
index ad873c2..0373e10 100644
--- a/ash/frame/non_client_frame_view_ash.h
+++ b/ash/frame/non_client_frame_view_ash.h
@@ -9,7 +9,6 @@
 
 #include "ash/ash_export.h"
 #include "ash/frame/header_view.h"
-#include "ash/public/cpp/split_view.h"
 #include "ash/wm/overview/overview_observer.h"
 #include "base/macros.h"
 #include "base/optional.h"
diff --git a/ash/home_screen/home_launcher_gesture_handler.cc b/ash/home_screen/home_launcher_gesture_handler.cc
index b6a56c4..84c908aa 100644
--- a/ash/home_screen/home_launcher_gesture_handler.cc
+++ b/ash/home_screen/home_launcher_gesture_handler.cc
@@ -641,7 +641,7 @@
 
   // Explicitly exit split view if two windows are snapped.
   if (is_final_state_show && Shell::Get()->split_view_controller()->state() ==
-                                 SplitViewState::kBothSnapped) {
+                                 SplitViewController::State::kBothSnapped) {
     Shell::Get()->split_view_controller()->EndSplitView();
   }
 
@@ -965,7 +965,8 @@
   // Alter a second window if we are in split view mode with two windows
   // snapped.
   if (mode == Mode::kSlideUpToShow &&
-      split_view_controller->state() == SplitViewState::kBothSnapped) {
+      split_view_controller->state() ==
+          SplitViewController::State::kBothSnapped) {
     DCHECK_GT(windows.size(), 0u);
     aura::Window* second_window =
         split_view_controller->default_snap_position() ==
diff --git a/ash/magnifier/docked_magnifier_controller_impl_unittest.cc b/ash/magnifier/docked_magnifier_controller_impl_unittest.cc
index 74f6f7f..5eae57b99 100644
--- a/ash/magnifier/docked_magnifier_controller_impl_unittest.cc
+++ b/ash/magnifier/docked_magnifier_controller_impl_unittest.cc
@@ -374,7 +374,8 @@
   WindowState::Get(window.get())->Maximize();
 
   auto* split_view_controller = Shell::Get()->split_view_controller();
-  EXPECT_EQ(split_view_controller->state(), SplitViewState::kNoSnap);
+  EXPECT_EQ(split_view_controller->state(),
+            SplitViewController::State::kNoSnap);
   EXPECT_EQ(split_view_controller->InSplitViewMode(), false);
 
   // Simulate going into split view, by enabling overview mode, and snapping
@@ -383,7 +384,8 @@
   overview_controller->StartOverview();
   EXPECT_TRUE(overview_controller->InOverviewSession());
   split_view_controller->SnapWindow(window.get(), SplitViewController::LEFT);
-  EXPECT_EQ(split_view_controller->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_EQ(split_view_controller->left_window(), window.get());
   EXPECT_TRUE(overview_controller->InOverviewSession());
 
@@ -393,7 +395,8 @@
   controller()->SetEnabled(true);
   EXPECT_TRUE(controller()->GetEnabled());
   EXPECT_FALSE(overview_controller->InOverviewSession());
-  EXPECT_EQ(split_view_controller->state(), SplitViewState::kNoSnap);
+  EXPECT_EQ(split_view_controller->state(),
+            SplitViewController::State::kNoSnap);
   EXPECT_EQ(split_view_controller->InSplitViewMode(), false);
   const display::Display& display = display_manager()->GetDisplayAt(0);
   const int magnifier_height = GetMagnifierHeight(display.bounds().height());
@@ -425,7 +428,8 @@
   split_view_controller->SnapWindow(window1.get(), SplitViewController::LEFT);
   split_view_controller->SnapWindow(window2.get(), SplitViewController::RIGHT);
   EXPECT_EQ(split_view_controller->InSplitViewMode(), true);
-  EXPECT_EQ(split_view_controller->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller->state(),
+            SplitViewController::State::kBothSnapped);
 
   // Snapping both windows should exit overview mode.
   EXPECT_FALSE(overview_controller->InOverviewSession());
@@ -436,7 +440,8 @@
   controller()->SetEnabled(true);
   EXPECT_TRUE(controller()->GetEnabled());
   EXPECT_EQ(split_view_controller->InSplitViewMode(), true);
-  EXPECT_EQ(split_view_controller->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller->state(),
+            SplitViewController::State::kBothSnapped);
   const display::Display& display = display_manager()->GetDisplayAt(0);
   const int magnifier_height = GetMagnifierHeight(display.bounds().height());
   gfx::Rect work_area = display.bounds();
diff --git a/ash/metrics/histogram_macros.cc b/ash/metrics/histogram_macros.cc
index 1fc303c..20ca3bfb 100644
--- a/ash/metrics/histogram_macros.cc
+++ b/ash/metrics/histogram_macros.cc
@@ -10,15 +10,15 @@
 namespace ash {
 
 bool InTabletMode() {
-  auto* shell = Shell::Get();
-  return shell && shell->tablet_mode_controller() &&
-         shell->tablet_mode_controller()->InTabletMode();
+  TabletModeController* tablet_mode_controller =
+      Shell::Get()->tablet_mode_controller();
+  return tablet_mode_controller && tablet_mode_controller->InTabletMode();
 }
 
 bool IsInSplitView() {
-  auto* shell = Shell::Get();
-  return shell && shell->split_view_controller() &&
-         shell->split_view_controller()->InSplitViewMode();
+  SplitViewController* split_view_controller =
+      Shell::Get()->split_view_controller();
+  return split_view_controller && split_view_controller->InSplitViewMode();
 }
 
 }  // namespace ash
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn
index d91777a..0820f3934 100644
--- a/ash/public/cpp/BUILD.gn
+++ b/ash/public/cpp/BUILD.gn
@@ -192,7 +192,6 @@
     "shell_window_ids.h",
     "shutdown_controller.cc",
     "shutdown_controller.h",
-    "split_view.h",
     "spoken_feedback_event_rewriter_delegate.h",
     "stylus_utils.cc",
     "stylus_utils.h",
diff --git a/ash/public/cpp/shelf_config.h b/ash/public/cpp/shelf_config.h
index 0d57d4d..09d245ce 100644
--- a/ash/public/cpp/shelf_config.h
+++ b/ash/public/cpp/shelf_config.h
@@ -63,6 +63,9 @@
   // width when the shelf is vertical).
   int shelf_size() const;
 
+  // Size of the shelf when an app is visible in tablet mode.
+  int in_app_shelf_size() const;
+
   // Size of the hotseat, which contains the scrollable shelf in tablet mode.
   int hotseat_size() const;
 
diff --git a/ash/public/cpp/split_view.h b/ash/public/cpp/split_view.h
deleted file mode 100644
index 6b92039..0000000
--- a/ash/public/cpp/split_view.h
+++ /dev/null
@@ -1,35 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef ASH_PUBLIC_CPP_SPLIT_VIEW_H_
-#define ASH_PUBLIC_CPP_SPLIT_VIEW_H_
-
-#include "ash/public/cpp/ash_public_export.h"
-
-namespace ash {
-
-enum class SplitViewState {
-  kNoSnap,
-  kLeftSnapped,
-  kRightSnapped,
-  kBothSnapped,
-};
-
-class ASH_PUBLIC_EXPORT SplitViewObserver {
- public:
-  // Called when split view state changed from |previous_state| to |state|.
-  virtual void OnSplitViewStateChanged(SplitViewState previous_state,
-                                       SplitViewState state) {}
-
-  // Called when split view divider's position has changed.
-  virtual void OnSplitViewDividerPositionChanged() {}
-
- protected:
-  SplitViewObserver() = default;
-  virtual ~SplitViewObserver() = default;
-};
-
-}  // namespace ash
-
-#endif  // ASH_PUBLIC_CPP_SPLIT_VIEW_H_
diff --git a/ash/shelf/shelf_config.cc b/ash/shelf/shelf_config.cc
index 1863734..21d73be 100644
--- a/ash/shelf/shelf_config.cc
+++ b/ash/shelf/shelf_config.cc
@@ -135,10 +135,14 @@
   if (!Shell::Get()->tablet_mode_controller()->InTabletMode())
     return 48;
 
-  if (is_dense_)
-    return is_in_app() ? 36 : 48;
-  else
-    return is_in_app() ? 40 : 56;
+  if (is_in_app())
+    return in_app_shelf_size();
+
+  return is_dense_ ? 48 : 56;
+}
+
+int ShelfConfig::in_app_shelf_size() const {
+  return is_dense_ ? 36 : 40;
 }
 
 int ShelfConfig::hotseat_size() const {
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc
index 0c690c5..4d6f68b 100644
--- a/ash/shelf/shelf_layout_manager.cc
+++ b/ash/shelf/shelf_layout_manager.cc
@@ -750,10 +750,11 @@
   UpdateVisibilityState();
 }
 
-void ShelfLayoutManager::OnSplitViewStateChanged(SplitViewState previous_state,
-                                                 SplitViewState state) {
-  if (previous_state == SplitViewState::kNoSnap ||
-      state == SplitViewState::kNoSnap) {
+void ShelfLayoutManager::OnSplitViewStateChanged(
+    SplitViewController::State previous_state,
+    SplitViewController::State state) {
+  if (previous_state == SplitViewController::State::kNoSnap ||
+      state == SplitViewController::State::kNoSnap) {
     MaybeUpdateShelfBackground(AnimationChangeType::ANIMATE);
   }
 }
@@ -1386,28 +1387,27 @@
   int hotseat_width;
   int hotseat_height;
   if (shelf_->IsHorizontalAlignment()) {
-    int hotseat_y;
-    const int hotseat_size = Shell::Get()->shelf_config()->hotseat_size();
+    int hotseat_distance_from_bottom_of_display;
+    const int hotseat_size = ShelfConfig::Get()->hotseat_size();
     switch (state_.hotseat_state) {
       case HotseatState::kShown: {
         // When the hotseat state is HotseatState::kShown in tablet mode, the
         // home launcher is showing. Elevate the hotseat a few px to match the
         // navigation and status area.
-        const bool use_padding = chromeos::switches::ShouldShowShelfHotseat() &&
-                                 IsTabletModeEnabled();
-        hotseat_y =
-            use_padding
-                ? -Shell::Get()->shelf_config()->hotseat_bottom_padding()
-                : 0;
+        const bool use_padding = IsHotseatEnabled();
+        hotseat_distance_from_bottom_of_display =
+            hotseat_size +
+            (use_padding ? ShelfConfig::Get()->hotseat_bottom_padding() : 0);
       } break;
       case HotseatState::kHidden:
         // Show the hotseat offscreen.
-        hotseat_y = hotseat_size;
+        hotseat_distance_from_bottom_of_display = 0;
         break;
       case HotseatState::kExtended:
         // Show the hotseat at its extended position.
-        hotseat_y = -hotseat_size -
-                    Shell::Get()->shelf_config()->hotseat_bottom_padding();
+        hotseat_distance_from_bottom_of_display =
+            ShelfConfig::Get()->in_app_shelf_size() +
+            ShelfConfig::Get()->hotseat_bottom_padding() + hotseat_size;
         break;
     }
 
@@ -1415,21 +1415,19 @@
         shelf_width - target_bounds->nav_bounds_in_shelf.size().width() -
         home_button_edge_spacing - ShelfConfig::Get()->app_icon_group_margin() -
         status_size.width();
-
     int hotseat_x = base::i18n::IsRTL()
                         ? target_bounds->nav_bounds_in_shelf.x() -
                               home_button_edge_spacing - hotseat_width
                         : target_bounds->nav_bounds_in_shelf.right() +
                               home_button_edge_spacing;
-
     if (state_.hotseat_state != HotseatState::kShown) {
       // Give the hotseat more space if it is shown outside of the shelf.
       hotseat_width = available_bounds.width();
       hotseat_x = 0;
     }
-
+    const int hotseat_y =
+        -(hotseat_distance_from_bottom_of_display - shelf_size);
     hotseat_origin = gfx::Point(hotseat_x, hotseat_y);
-
     hotseat_height = hotseat_size;
   } else {
     hotseat_origin = gfx::Point(0, target_bounds->nav_bounds_in_shelf.bottom() +
diff --git a/ash/shelf/shelf_layout_manager.h b/ash/shelf/shelf_layout_manager.h
index 069616df..93e8eb4 100644
--- a/ash/shelf/shelf_layout_manager.h
+++ b/ash/shelf/shelf_layout_manager.h
@@ -11,7 +11,6 @@
 #include "ash/home_screen/home_launcher_gesture_handler_observer.h"
 #include "ash/public/cpp/app_list/app_list_controller_observer.h"
 #include "ash/public/cpp/shelf_types.h"
-#include "ash/public/cpp/split_view.h"
 #include "ash/public/cpp/wallpaper_controller.h"
 #include "ash/public/cpp/wallpaper_controller_observer.h"
 #include "ash/session/session_observer.h"
@@ -21,6 +20,8 @@
 #include "ash/wm/desks/desks_controller.h"
 #include "ash/wm/lock_state_observer.h"
 #include "ash/wm/overview/overview_observer.h"
+#include "ash/wm/splitview/split_view_controller.h"
+#include "ash/wm/splitview/split_view_observer.h"
 #include "ash/wm/wm_default_layout_manager.h"
 #include "ash/wm/workspace/workspace_types.h"
 #include "base/macros.h"
@@ -174,8 +175,8 @@
   void OnPinnedStateChanged(aura::Window* pinned_window) override;
 
   // SplitViewObserver:
-  void OnSplitViewStateChanged(SplitViewState previous_state,
-                               SplitViewState state) override;
+  void OnSplitViewStateChanged(SplitViewController::State previous_state,
+                               SplitViewController::State state) override;
 
   // OverviewObserver:
   void OnOverviewModeStarting() override;
diff --git a/ash/wm/desks/desks_unittests.cc b/ash/wm/desks/desks_unittests.cc
index cc0e350..5851eb61 100644
--- a/ash/wm/desks/desks_unittests.cc
+++ b/ash/wm/desks/desks_unittests.cc
@@ -1692,7 +1692,8 @@
     waiter.Wait();
   }
   EXPECT_TRUE(WindowState::Get(win1.get())->IsSnapped());
-  EXPECT_EQ(SplitViewState::kNoSnap, split_view_controller->state());
+  EXPECT_EQ(SplitViewController::State::kNoSnap,
+            split_view_controller->state());
   EXPECT_FALSE(overview_controller->InOverviewSession());
 
   // Switch back to |desk_1| and verify that split view is arranged as before.
@@ -1709,7 +1710,8 @@
     waiter.Wait();
   }
   EXPECT_TRUE(WindowState::Get(win1.get())->IsSnapped());
-  EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
+  EXPECT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller->state());
   EXPECT_EQ(win1.get(), split_view_controller->left_window());
   EXPECT_TRUE(overview_controller->InOverviewSession());
 }
@@ -1771,7 +1773,8 @@
   RemoveDesk(desk_2);
   EXPECT_EQ(win1.get(), split_view_controller->left_window());
   EXPECT_EQ(win2.get(), split_view_controller->right_window());
-  EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller->state());
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller->state());
 }
 
 TEST_F(TabletModeDesksTest, RemoveDeskWithMaximizedWindowAndMergeWithSnapped) {
@@ -1797,7 +1800,8 @@
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   EXPECT_EQ(win1.get(), split_view_controller->left_window());
   EXPECT_EQ(nullptr, split_view_controller->right_window());
-  EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
+  EXPECT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller->state());
 }
 
 TEST_F(TabletModeDesksTest, BackdropsStacking) {
diff --git a/ash/wm/overview/overview_controller.cc b/ash/wm/overview/overview_controller.cc
index 0287b8cb..2b98777 100644
--- a/ash/wm/overview/overview_controller.cc
+++ b/ash/wm/overview/overview_controller.cc
@@ -637,15 +637,17 @@
     // between user sessions, or on transition between virtual desks. Those are
     // the cases where code arranges split view by first snapping a window on
     // one side and then starting overview to be seen on the other side, meaning
-    // that the split view state here will be |SplitViewState::kLeftSnapped| or
-    // |SplitViewState::kRightSnapped|. We have to check the split view state
-    // before |SplitViewController::OnOverviewModeStarting|, because in case of
-    // |SplitViewState::kBothSnapped|, that function will insert one of the two
-    // snapped windows to overview.
-    const SplitViewState split_view_state =
+    // that the split view state here will be
+    // |SplitViewController::State::kLeftSnapped| or
+    // |SplitViewController::State::kRightSnapped|. We have to check the split
+    // view state before |SplitViewController::OnOverviewModeStarting|, because
+    // in case of |SplitViewController::State::kBothSnapped|, that function will
+    // insert one of the two snapped windows to overview.
+    const SplitViewController::State split_view_state =
         Shell::Get()->split_view_controller()->state();
-    should_focus_overview_ = split_view_state == SplitViewState::kNoSnap ||
-                             split_view_state == SplitViewState::kBothSnapped;
+    should_focus_overview_ =
+        split_view_state == SplitViewController::State::kNoSnap ||
+        split_view_state == SplitViewController::State::kBothSnapped;
 
     // Suspend occlusion tracker until the enter animation is complete.
     PauseOcclusionTracker();
@@ -719,7 +721,8 @@
   // up from the shelf in tablet mode, or ending overview immediately without
   // animations.
   if (split_view_controller->InTabletSplitViewMode() &&
-      split_view_controller->state() != SplitViewState::kBothSnapped &&
+      split_view_controller->state() !=
+          SplitViewController::State::kBothSnapped &&
       InOverviewSession() && overview_session_->IsEmpty() &&
       type != OverviewSession::EnterExitOverviewType::kSwipeFromShelf &&
       type != OverviewSession::EnterExitOverviewType::kImmediateExit) {
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc
index a8eaff09..0b7b0f4 100644
--- a/ash/wm/overview/overview_grid.cc
+++ b/ash/wm/overview/overview_grid.cc
@@ -223,10 +223,10 @@
   SplitViewController* split_view_controller =
       Shell::Get()->split_view_controller();
   switch (split_view_controller->state()) {
-    case SplitViewState::kLeftSnapped:
+    case SplitViewController::State::kLeftSnapped:
       return split_view_controller->GetSnappedWindowBoundsInScreen(
           dragged_window, SplitViewController::RIGHT);
-    case SplitViewState::kRightSnapped:
+    case SplitViewController::State::kRightSnapped:
       return split_view_controller->GetSnappedWindowBoundsInScreen(
           dragged_window, SplitViewController::LEFT);
     default:
diff --git a/ash/wm/overview/overview_item.cc b/ash/wm/overview/overview_item.cc
index 4b34fe8..4c4bab4 100644
--- a/ash/wm/overview/overview_item.cc
+++ b/ash/wm/overview/overview_item.cc
@@ -493,9 +493,10 @@
       overview_grid_->IsDropTargetWindow(GetWindow())) {
     visible = false;
   } else {
-    const SplitViewState state = Shell::Get()->split_view_controller()->state();
-    visible = state == SplitViewState::kLeftSnapped ||
-              state == SplitViewState::kRightSnapped;
+    const SplitViewController::State state =
+        Shell::Get()->split_view_controller()->state();
+    visible = state == SplitViewController::State::kLeftSnapped ||
+              state == SplitViewController::State::kRightSnapped;
   }
 
   if (!visible && !cannot_snap_widget_)
diff --git a/ash/wm/overview/overview_session.cc b/ash/wm/overview/overview_session.cc
index c4379aa..9f8eaa8 100644
--- a/ash/wm/overview/overview_session.cc
+++ b/ash/wm/overview/overview_session.cc
@@ -946,26 +946,29 @@
   EndOverview();
 }
 
-void OverviewSession::OnSplitViewStateChanged(SplitViewState previous_state,
-                                              SplitViewState state) {
+void OverviewSession::OnSplitViewStateChanged(
+    SplitViewController::State previous_state,
+    SplitViewController::State state) {
   // Do nothing if overview is being shutdown.
   if (!Shell::Get()->overview_controller()->InOverviewSession())
     return;
 
   const bool unsnappable_window_activated =
-      state == SplitViewState::kNoSnap &&
+      state == SplitViewController::State::kNoSnap &&
       Shell::Get()->split_view_controller()->end_reason() ==
           SplitViewController::EndReason::kUnsnappableWindowActivated;
 
   // Restore focus unless either a window was just snapped (and activated) or
   // split view mode was ended by activating an unsnappable window.
-  if (state != SplitViewState::kNoSnap || unsnappable_window_activated)
+  if (state != SplitViewController::State::kNoSnap ||
+      unsnappable_window_activated)
     ResetFocusRestoreWindow(false);
 
   // If two windows were snapped to both sides of the screen or an unsnappable
   // window was just activated, or we're in single split mode in clamshell mode
   // and there is no window in overview, end overview mode and bail out.
-  if (state == SplitViewState::kBothSnapped || unsnappable_window_activated ||
+  if (state == SplitViewController::State::kBothSnapped ||
+      unsnappable_window_activated ||
       (Shell::Get()->split_view_controller()->InClamshellSplitViewMode() &&
        IsEmpty())) {
     EndOverview();
diff --git a/ash/wm/overview/overview_session.h b/ash/wm/overview/overview_session.h
index 671517f..3b17ad0 100644
--- a/ash/wm/overview/overview_session.h
+++ b/ash/wm/overview/overview_session.h
@@ -12,9 +12,10 @@
 #include <vector>
 
 #include "ash/ash_export.h"
-#include "ash/public/cpp/split_view.h"
 #include "ash/shell_observer.h"
 #include "ash/wm/overview/scoped_overview_hide_windows.h"
+#include "ash/wm/splitview/split_view_controller.h"
+#include "ash/wm/splitview/split_view_observer.h"
 #include "base/containers/flat_set.h"
 #include "base/macros.h"
 #include "base/time/time.h"
@@ -260,8 +261,8 @@
   void OnKeyEvent(ui::KeyEvent* event) override;
 
   // SplitViewObserver:
-  void OnSplitViewStateChanged(SplitViewState previous_state,
-                               SplitViewState state) override;
+  void OnSplitViewStateChanged(SplitViewController::State previous_state,
+                               SplitViewController::State state) override;
   void OnSplitViewDividerPositionChanged() override;
 
   OverviewDelegate* delegate() { return delegate_; }
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc
index 801aaa6e..963b920 100644
--- a/ash/wm/overview/overview_session_unittest.cc
+++ b/ash/wm/overview/overview_session_unittest.cc
@@ -1299,9 +1299,7 @@
 
 // Tests that dragging a window from overview creates a drop target on the same
 // display.
-// Disabled, test is flaky: crbug.com/1008408
-TEST_P(OverviewSessionTest,
-       DISABLED_DropTargetOnCorrectDisplayForDraggingFromOverview) {
+TEST_P(OverviewSessionTest, DropTargetOnCorrectDisplayForDraggingFromOverview) {
   UpdateDisplay("600x600,600x600");
   EnterTabletMode();
   // DisplayConfigurationObserver enables mirror mode when tablet mode is
@@ -2959,7 +2957,8 @@
   // z-order now, since it is the MRU window.
   split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
   ToggleOverview();
-  ASSERT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state());
+  ASSERT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller()->state());
   ASSERT_GT(IndexOf(window2.get(), window2->parent()),
             IndexOf(window1.get(), window1->parent()));
 
@@ -3143,7 +3142,8 @@
   overview_session()->CompleteDrag(overview_item1, snap_left_location);
 
   ASSERT_TRUE(split_view_controller()->InSplitViewMode());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window1.get());
 
   // Dispatches a long press event at the |overview_item2|'s current location to
@@ -3162,7 +3162,8 @@
 
   EXPECT_FALSE(InOverviewSession());
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(split_view_controller()->right_window(), window2.get());
 }
 
@@ -3328,7 +3329,8 @@
   DragWindowTo(overview_item1, gfx::PointF(0, 0));
 
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window1.get());
 
   // Drag |window2| selector item to attempt to snap to left. Since there is
@@ -3337,7 +3339,8 @@
   OverviewItem* overview_item2 = GetOverviewItemForWindow(window2.get());
   DragWindowTo(overview_item2, gfx::PointF(0, 0));
 
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window2.get());
   EXPECT_TRUE(overview_controller()->overview_session()->IsWindowInOverview(
       window1.get()));
@@ -3348,7 +3351,8 @@
                                   0.f);
   DragWindowTo(overview_item3, end_location3);
 
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(split_view_controller()->right_window(), window3.get());
   EXPECT_FALSE(overview_controller()->InOverviewSession());
 }
@@ -3629,7 +3633,8 @@
   const gfx::PointF left(0, 0);
   overview_session()->Drag(overview_item, left);
   EXPECT_FALSE(split_view_controller()->InSplitViewMode());
-  EXPECT_EQ(SplitViewState::kNoSnap, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kNoSnap,
+            split_view_controller()->state());
   EXPECT_TRUE(split_view_controller()->left_window() == nullptr);
   EXPECT_EQ(GetSplitViewRightWindowBounds(window1.get()), GetGridBounds());
 
@@ -3637,7 +3642,8 @@
   // left window of split view mode should be.
   const gfx::PointF right(window_width, 0);
   overview_session()->Drag(overview_item, right);
-  EXPECT_EQ(SplitViewState::kNoSnap, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kNoSnap,
+            split_view_controller()->state());
   EXPECT_TRUE(split_view_controller()->right_window() == nullptr);
   EXPECT_EQ(GetSplitViewLeftWindowBounds(window1.get()), GetGridBounds());
 
@@ -3645,13 +3651,15 @@
   // dimensions of the work area.
   const gfx::PointF center(window_width / 2, 0);
   overview_session()->Drag(overview_item, center);
-  EXPECT_EQ(SplitViewState::kNoSnap, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kNoSnap,
+            split_view_controller()->state());
   EXPECT_EQ(GetWorkAreaInScreen(window1.get()), GetGridBounds());
 
   // Snap window1 to the left and initialize dragging for window2.
   overview_session()->Drag(overview_item, left);
   overview_session()->CompleteDrag(overview_item, left);
-  ASSERT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state());
+  ASSERT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller()->state());
   ASSERT_EQ(window1.get(), split_view_controller()->left_window());
   overview_item = GetOverviewItemForWindow(window2.get());
   overview_item_bounds = overview_item->target_bounds();
@@ -3717,14 +3725,16 @@
 
   // Test that overview mode is active in this single window case.
   EXPECT_EQ(split_view_controller()->InSplitViewMode(), true);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_TRUE(overview_controller()->InOverviewSession());
 
   // Create a new window should exit the overview mode.
   std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
   wm::ActivateWindow(window2.get());
   EXPECT_FALSE(overview_controller()->InOverviewSession());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   // If there are only 2 snapped windows, close one of them should enter
   // overview mode.
   window2.reset();
@@ -3736,7 +3746,8 @@
   wm::ActivateWindow(window3.get());
   wm::ActivateWindow(window4.get());
   EXPECT_FALSE(overview_controller()->InOverviewSession());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   ToggleOverview();
   EXPECT_TRUE(overview_controller()->InOverviewSession());
   window3.reset();
@@ -3801,7 +3812,8 @@
   // Test that dragging |window1| to the left of the screen snaps it to left.
   OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
   DragWindowTo(overview_item1, gfx::PointF());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window1.get());
 
   // Test that dragging |window2| to the right of the screen snaps it to right.
@@ -3809,7 +3821,8 @@
   gfx::Rect work_area_rect = GetWorkAreaInScreen(window2.get());
   gfx::PointF end_location2(work_area_rect.width(), work_area_rect.height());
   DragWindowTo(overview_item2, end_location2);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(split_view_controller()->right_window(), window2.get());
 
   // Test that |left_window_| was snapped to left after rotated 0 degree.
@@ -3829,7 +3842,8 @@
   // Test that dragging |window1| to the top of the screen snaps it to left.
   overview_item1 = GetOverviewItemForWindow(window1.get());
   DragWindowTo(overview_item1, gfx::PointF(0, 0));
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window1.get());
 
   // Test that dragging |window2| to the bottom of the screen snaps it to right.
@@ -3837,7 +3851,8 @@
   work_area_rect = GetWorkAreaInScreen(window2.get());
   end_location2 = gfx::PointF(work_area_rect.width(), work_area_rect.height());
   DragWindowTo(overview_item2, end_location2, SelectorItemLocation::ORIGIN);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(split_view_controller()->right_window(), window2.get());
 
   // Test that |left_window_| was snapped to top after rotated 270 degree.
@@ -3857,7 +3872,8 @@
   // Test that dragging |window1| to the left of the screen snaps it to right.
   overview_item1 = GetOverviewItemForWindow(window1.get());
   DragWindowTo(overview_item1, gfx::PointF());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kRightSnapped);
   EXPECT_EQ(split_view_controller()->right_window(), window1.get());
 
   // Test that dragging |window2| to the right of the screen snaps it to left.
@@ -3865,7 +3881,8 @@
   work_area_rect = GetWorkAreaInScreen(window2.get());
   end_location2 = gfx::PointF(work_area_rect.width(), work_area_rect.height());
   DragWindowTo(overview_item2, end_location2, SelectorItemLocation::ORIGIN);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window2.get());
 
   // Test that |right_window_| was snapped to left after rotated 180 degree.
@@ -3885,7 +3902,8 @@
   // Test that dragging |window1| to the top of the screen snaps it to right.
   overview_item1 = GetOverviewItemForWindow(window1.get());
   DragWindowTo(overview_item1, gfx::PointF(0, 0));
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kRightSnapped);
   EXPECT_EQ(split_view_controller()->right_window(), window1.get());
 
   // Test that dragging |window2| to the bottom of the screen snaps it to left.
@@ -3893,7 +3911,8 @@
   work_area_rect = GetWorkAreaInScreen(window2.get());
   end_location2 = gfx::PointF(work_area_rect.width(), work_area_rect.height());
   DragWindowTo(overview_item2, end_location2);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window2.get());
 
   // Test that |right_window_| was snapped to top after rotated 90 degree.
@@ -3921,7 +3940,8 @@
   OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
   DragWindowTo(overview_item1, gfx::PointF());
 
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   const gfx::Rect window1_bounds = window1->GetBoundsInScreen();
   const gfx::Rect overview_grid_bounds = GetGridBounds();
   const gfx::Rect divider_bounds =
@@ -3990,12 +4010,14 @@
 
   // Split view mode should be active. Overview mode should be ended.
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
-  EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller()->state());
   EXPECT_FALSE(overview_controller()->InOverviewSession());
 
   ToggleOverview();
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
-  EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller()->state());
   EXPECT_TRUE(overview_controller()->InOverviewSession());
 
   // Now select the unsnappable window.
@@ -4153,7 +4175,8 @@
   // Drag |window1| selector item to snap to left.
   OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
   DragWindowTo(overview_item1, gfx::PointF());
-  EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller()->state());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
 
   // Then drag the divider to left toward closing the snapped window.
@@ -4178,7 +4201,8 @@
   gfx::Point end_location2 =
       gfx::Point(work_area_rect.width(), work_area_rect.height());
   DragWindowTo(overview_item2, gfx::PointF(end_location2));
-  EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kRightSnapped,
+            split_view_controller()->state());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
 
   // Then drag the divider to right toward closing the snapped window.
@@ -4214,7 +4238,8 @@
   // the overview grid afterwards, |window2| and |window3|.
   OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
   DragWindowTo(overview_item1, gfx::PointF());
-  EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller()->state());
   EXPECT_TRUE(InOverviewSession());
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   ASSERT_TRUE(split_view_controller()->split_view_divider());
@@ -4311,7 +4336,8 @@
   ToggleOverview();
   OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
   DragWindowTo(overview_item1, gfx::PointF());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window1.get());
   EXPECT_TRUE(InOverviewSession());
 
@@ -4326,14 +4352,16 @@
   DragWindowTo(overview_item1, gfx::PointF());
   wm::ActivateWindow(window2.get());
   EXPECT_FALSE(InOverviewSession());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window1.get());
   EXPECT_EQ(split_view_controller()->right_window(), window2.get());
 
   // Minimize |window1| will open overview and put |window1| to overview grid.
   WindowState::Get(window1.get())->Minimize();
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kRightSnapped);
   EXPECT_TRUE(InOverviewSession());
   EXPECT_TRUE(GetOverviewItemForWindow(window1.get()));
 
@@ -4366,7 +4394,8 @@
   EXPECT_FALSE(window3->layer()->GetTargetTransform().IsIdentity());
   OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
   DragWindowTo(overview_item1, gfx::PointF());
-  EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller()->state());
   // Drag |window2| to snap to right.
   OverviewItem* overview_item2 = GetOverviewItemForWindow(window2.get());
   const gfx::Rect work_area_rect =
@@ -4374,7 +4403,8 @@
           window2.get());
   const gfx::PointF end_location2(work_area_rect.width(), 0);
   DragWindowTo(overview_item2, end_location2);
-  EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller()->state());
   EXPECT_FALSE(overview_controller()->InOverviewSession());
   EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity());
   EXPECT_TRUE(window2->layer()->GetTargetTransform().IsIdentity());
@@ -4387,10 +4417,12 @@
   EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity());
   EXPECT_FALSE(window2->layer()->GetTargetTransform().IsIdentity());
   EXPECT_FALSE(window3->layer()->GetTargetTransform().IsIdentity());
-  EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller()->state());
   // ToggleOverview() directly.
   ToggleOverview();
-  EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller()->state());
   EXPECT_FALSE(overview_controller()->InOverviewSession());
   EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity());
   EXPECT_TRUE(window2->layer()->GetTargetTransform().IsIdentity());
@@ -4401,9 +4433,11 @@
   EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity());
   EXPECT_FALSE(window2->layer()->GetTargetTransform().IsIdentity());
   EXPECT_FALSE(window3->layer()->GetTargetTransform().IsIdentity());
-  EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller()->state());
   wm::ActivateWindow(window2.get());
-  EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller()->state());
   EXPECT_FALSE(overview_controller()->InOverviewSession());
   EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity());
   EXPECT_TRUE(window2->layer()->GetTargetTransform().IsIdentity());
@@ -4414,10 +4448,12 @@
   EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity());
   EXPECT_FALSE(window2->layer()->GetTargetTransform().IsIdentity());
   EXPECT_FALSE(window3->layer()->GetTargetTransform().IsIdentity());
-  EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller()->state());
   std::unique_ptr<aura::Window> window4(CreateWindow(bounds));
   wm::ActivateWindow(window4.get());
-  EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller()->state());
   EXPECT_FALSE(overview_controller()->InOverviewSession());
   EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity());
   EXPECT_TRUE(window2->layer()->GetTargetTransform().IsIdentity());
@@ -4436,7 +4472,8 @@
   ToggleOverview();
   OverviewItem* overview_item1 = GetOverviewItemForWindow(window1.get());
   DragWindowTo(overview_item1, gfx::PointF());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_EQ(split_view_controller()->default_snap_position(),
             SplitViewController::LEFT);
   EXPECT_TRUE(overview_controller()->InOverviewSession());
@@ -4445,7 +4482,8 @@
                 window1.get(), SplitViewController::RIGHT));
 
   split_view_controller()->SwapWindows();
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kRightSnapped);
   EXPECT_EQ(split_view_controller()->default_snap_position(),
             SplitViewController::RIGHT);
   EXPECT_EQ(GetGridBounds(),
diff --git a/ash/wm/overview/overview_window_drag_controller.cc b/ash/wm/overview/overview_window_drag_controller.cc
index 1ebd144..d129338 100644
--- a/ash/wm/overview/overview_window_drag_controller.cc
+++ b/ash/wm/overview/overview_window_drag_controller.cc
@@ -291,11 +291,12 @@
   // right window, snap the current window to left. If split view is active
   // and the selected window cannot be snapped, exit splitview and activate
   // the selected window, and also exit the overview.
-  SplitViewState split_state = split_view_controller_->state();
-  if (!should_allow_split_view_ || split_state == SplitViewState::kNoSnap) {
+  SplitViewController::State split_state = split_view_controller_->state();
+  if (!should_allow_split_view_ ||
+      split_state == SplitViewController::State::kNoSnap) {
     overview_session_->SelectWindow(item_);
   } else if (CanSnapInSplitview(item_->GetWindow())) {
-    SnapWindow(split_state == SplitViewState::kLeftSnapped
+    SnapWindow(split_state == SplitViewController::State::kLeftSnapped
                    ? SplitViewController::RIGHT
                    : SplitViewController::LEFT);
   } else {
diff --git a/ash/wm/overview/overview_window_drag_controller_unittest.cc b/ash/wm/overview/overview_window_drag_controller_unittest.cc
index ed13934..f5e39e0 100644
--- a/ash/wm/overview/overview_window_drag_controller_unittest.cc
+++ b/ash/wm/overview/overview_window_drag_controller_unittest.cc
@@ -448,7 +448,8 @@
   // remains unshifted.
   event_generator->ReleaseLeftButton();
   EXPECT_TRUE(overview_controller()->InOverviewSession());
-  EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller()->state());
   EXPECT_EQ(window.get(), split_view_controller()->left_window());
   EXPECT_EQ(overview_grid()->bounds().y(),
             desks_bar_widget()->GetWindowBoundsInScreen().y());
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc
index 5ad0e10..ccbb6a3 100644
--- a/ash/wm/splitview/split_view_controller.cc
+++ b/ash/wm/splitview/split_view_controller.cc
@@ -24,6 +24,7 @@
 #include "ash/wm/overview/overview_utils.h"
 #include "ash/wm/splitview/split_view_constants.h"
 #include "ash/wm/splitview/split_view_divider.h"
+#include "ash/wm/splitview/split_view_observer.h"
 #include "ash/wm/splitview/split_view_utils.h"
 #include "ash/wm/tablet_mode/tablet_mode_controller.h"
 #include "ash/wm/tablet_mode/tablet_mode_window_state.h"
@@ -292,12 +293,12 @@
 }
 
 bool SplitViewController::InClamshellSplitViewMode() const {
-  return state_ != SplitViewState::kNoSnap &&
+  return state_ != State::kNoSnap &&
          split_view_type_ == SplitViewType::kClamshellType;
 }
 
 bool SplitViewController::InTabletSplitViewMode() const {
-  return state_ != SplitViewState::kNoSnap &&
+  return state_ != State::kNoSnap &&
          split_view_type_ == SplitViewType::kTabletType;
 }
 
@@ -319,7 +320,7 @@
   RemoveWindowFromOverviewIfApplicable(window);
 
   bool do_divider_spawn_animation = false;
-  if (state_ == SplitViewState::kNoSnap) {
+  if (state_ == State::kNoSnap) {
     // Add observers when the split view mode starts.
     Shell::Get()->AddShellObserver(this);
     Shell::Get()->overview_controller()->AddObserver(this);
@@ -396,7 +397,7 @@
     // Update the divider position and window bounds before snapping a new
     // window. Since the minimum size of |window| maybe larger than currently
     // bounds in |snap_position|.
-  if (state_ != SplitViewState::kNoSnap &&
+  if (state_ != State::kNoSnap &&
       split_view_type_ == SplitViewType::kTabletType) {
     divider_position_ = GetClosestFixedDividerPosition();
     UpdateSnappedWindowsAndDividerBounds();
@@ -478,7 +479,7 @@
 
   divider_position_ = GetClosestFixedDividerPosition();
   UpdateSnappedWindowsAndDividerBounds();
-  UpdateSplitViewStateAndNotifyObservers();
+  UpdateStateAndNotifyObservers();
 
   base::RecordAction(
       base::UserMetricsAction("SplitView_DoubleTapDividerSwapWindows"));
@@ -585,7 +586,7 @@
   }
 
   base::RecordAction(base::UserMetricsAction("SplitView_ResizeWindows"));
-  if (state_ == SplitViewState::kBothSnapped) {
+  if (state_ == State::kBothSnapped) {
     presentation_time_recorder_ = CreatePresentationTimeHistogramRecorder(
         split_view_divider_->divider_widget()->GetCompositor(),
         kSplitViewResizeMultiHistogram,
@@ -698,7 +699,7 @@
   divider_closest_ratio_ = std::numeric_limits<float>::quiet_NaN();
   snapping_window_transformed_bounds_map_.clear();
 
-  UpdateSplitViewStateAndNotifyObservers();
+  UpdateStateAndNotifyObservers();
   base::RecordAction(base::UserMetricsAction("SplitView_EndSplitView"));
   UMA_HISTOGRAM_LONG_TIMES("Ash.SplitView.TimeInSplitView",
                            base::Time::Now() - splitview_start_time_);
@@ -987,7 +988,7 @@
   } else if (default_snap_position_ == RIGHT) {
     StopObserving(LEFT);
   }
-  UpdateSplitViewStateAndNotifyObservers();
+  UpdateStateAndNotifyObservers();
 }
 
 void SplitViewController::OnOverviewModeEnding(
@@ -1005,7 +1006,7 @@
 
   // If overview is ended because of a window getting snapped, suppress the
   // overview exiting animation.
-  if (state_ == SplitViewState::kBothSnapped)
+  if (state_ == State::kBothSnapped)
     overview_session->SetWindowListNotAnimatedWhenExiting(root_window);
 
   // If clamshell split view mode is active, end it and bail out.
@@ -1016,7 +1017,7 @@
 
   // Tablet split view mode is active. If it still only has one snapped window,
   // snap the first snappable window in the overview grid on the other side.
-  if (state_ == SplitViewState::kBothSnapped)
+  if (state_ == State::kBothSnapped)
     return;
   OverviewGrid* current_grid =
       overview_session->GetGridWithRootWindow(root_window);
@@ -1209,26 +1210,25 @@
   }
 }
 
-void SplitViewController::UpdateSplitViewStateAndNotifyObservers() {
-  SplitViewState previous_state = state_;
+void SplitViewController::UpdateStateAndNotifyObservers() {
+  State previous_state = state_;
   if (IsSnapped(left_window_) && IsSnapped(right_window_))
-    state_ = SplitViewState::kBothSnapped;
+    state_ = State::kBothSnapped;
   else if (IsSnapped(left_window_))
-    state_ = SplitViewState::kLeftSnapped;
+    state_ = State::kLeftSnapped;
   else if (IsSnapped(right_window_))
-    state_ = SplitViewState::kRightSnapped;
+    state_ = State::kRightSnapped;
   else
-    state_ = SplitViewState::kNoSnap;
+    state_ = State::kNoSnap;
 
   // We still notify observers even if |state_| doesn't change as it's possible
   // to snap a window to a position that already has a snapped window. However,
-  // |previous_state| and |state_| cannot both be |SplitViewState::kNoSnap|.
-  // When |previous_state| is |SplitViewState::kNoSnap|, it indicates to
+  // |previous_state| and |state_| cannot both be |State::kNoSnap|.
+  // When |previous_state| is |State::kNoSnap|, it indicates to
   // observers that split view mode started. Likewise, when |state_| is
-  // |SplitViewState::kNoSnap|, it indicates to observers that split view mode
+  // |State::kNoSnap|, it indicates to observers that split view mode
   // ended.
-  DCHECK(previous_state != SplitViewState::kNoSnap ||
-         state_ != SplitViewState::kNoSnap);
+  DCHECK(previous_state != State::kNoSnap || state_ != State::kNoSnap);
   for (auto& observer : observers_)
     observer.OnSplitViewStateChanged(previous_state, state_);
 }
@@ -1501,7 +1501,7 @@
 
 void SplitViewController::OnWindowSnapped(aura::Window* window) {
   RestoreTransformIfApplicable(window);
-  UpdateSplitViewStateAndNotifyObservers();
+  UpdateStateAndNotifyObservers();
   UpdateWindowStackingAfterSnap(window);
 }
 
@@ -1530,7 +1530,7 @@
     // If there is still one snapped window after minimizing/closing one snapped
     // window, update its snap state and open overview window grid.
     default_snap_position_ = left_window_ ? LEFT : RIGHT;
-    UpdateSplitViewStateAndNotifyObservers();
+    UpdateStateAndNotifyObservers();
     Shell::Get()->overview_controller()->StartOverview(
         window_drag ? OverviewSession::EnterExitOverviewType::kImmediateEnter
                     : OverviewSession::EnterExitOverviewType::kNormal);
diff --git a/ash/wm/splitview/split_view_controller.h b/ash/wm/splitview/split_view_controller.h
index 6094949..7ecc77f3 100644
--- a/ash/wm/splitview/split_view_controller.h
+++ b/ash/wm/splitview/split_view_controller.h
@@ -10,7 +10,6 @@
 
 #include "ash/accessibility/accessibility_observer.h"
 #include "ash/ash_export.h"
-#include "ash/public/cpp/split_view.h"
 #include "ash/public/cpp/tablet_mode_observer.h"
 #include "ash/shell_observer.h"
 #include "ash/wm/overview/overview_observer.h"
@@ -35,6 +34,7 @@
 class OverviewSession;
 class SplitViewControllerTest;
 class SplitViewDivider;
+class SplitViewObserver;
 class SplitViewOverviewSessionTest;
 
 // The controller for the split view. It snaps a window to left/right side of
@@ -87,6 +87,13 @@
     kClamshellType,
   };
 
+  enum class State {
+    kNoSnap,
+    kLeftSnapped,
+    kRightSnapped,
+    kBothSnapped,
+  };
+
   SplitViewController();
   ~SplitViewController() override;
 
@@ -214,7 +221,7 @@
   aura::Window* left_window() { return left_window_; }
   aura::Window* right_window() { return right_window_; }
   int divider_position() const { return divider_position_; }
-  SplitViewState state() const { return state_; }
+  State state() const { return state_; }
   SnapPosition default_snap_position() const { return default_snap_position_; }
   SplitViewDivider* split_view_divider() { return split_view_divider_.get(); }
   bool is_resizing() const { return is_resizing_; }
@@ -238,7 +245,7 @@
   void StopObserving(SnapPosition snap_position);
 
   // Update split view state and notify its observer about the change.
-  void UpdateSplitViewStateAndNotifyObservers();
+  void UpdateStateAndNotifyObservers();
 
   // Notifies observers that the split view divider position has been changed.
   void NotifyDividerPositionChanged();
@@ -406,7 +413,7 @@
   // to left or right, the left and right window will be resized accordingly.
   std::unique_ptr<SplitViewDivider> split_view_divider_;
 
-  // A black scrim layer that fades in over a window when it’s width drops under
+  // A black scrim layer that fades in over a window when its width drops under
   // 1/3 of the width of the screen, increasing in opacity as the divider gets
   // closer to the edge of the screen.
   std::unique_ptr<ui::Layer> black_scrim_layer_;
@@ -437,7 +444,7 @@
   std::unique_ptr<DividerSnapAnimation> divider_snap_animation_;
 
   // Current snap state.
-  SplitViewState state_ = SplitViewState::kNoSnap;
+  State state_ = State::kNoSnap;
 
   // The default snap position. It's decided by the first snapped window. If the
   // first window was snapped left, then |default_snap_position_| equals LEFT,
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc
index bdfcd35..2b25eba 100644
--- a/ash/wm/splitview/split_view_controller_unittest.cc
+++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -282,11 +282,13 @@
   std::unique_ptr<aura::Window> window1(CreateWindow(bounds));
   std::unique_ptr<aura::Window> window2(CreateWindow(bounds));
 
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kNoSnap);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kNoSnap);
   EXPECT_EQ(split_view_controller()->InSplitViewMode(), false);
 
   split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window1.get());
   EXPECT_NE(split_view_controller()->left_window(), window2.get());
   EXPECT_EQ(split_view_controller()->InSplitViewMode(), true);
@@ -296,7 +298,8 @@
 
   split_view_controller()->SnapWindow(window2.get(),
                                       SplitViewController::RIGHT);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(split_view_controller()->right_window(), window2.get());
   EXPECT_NE(split_view_controller()->right_window(), window1.get());
   EXPECT_EQ(split_view_controller()->InSplitViewMode(), true);
@@ -305,7 +308,8 @@
                 window2.get(), SplitViewController::RIGHT));
 
   EndSplitView();
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kNoSnap);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kNoSnap);
   EXPECT_EQ(split_view_controller()->InSplitViewMode(), false);
 }
 
@@ -352,14 +356,16 @@
   split_view_controller()->SnapWindow(window2.get(),
                                       SplitViewController::RIGHT);
   EXPECT_EQ(split_view_controller()->InSplitViewMode(), true);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(split_view_controller()->default_snap_position(),
             SplitViewController::LEFT);
 
   // Closing one of the two snapped windows will not end split view mode.
   window1.reset();
   EXPECT_EQ(split_view_controller()->InSplitViewMode(), true);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kRightSnapped);
   // Since left window was closed, its default snap position changed to RIGHT.
   EXPECT_EQ(split_view_controller()->default_snap_position(),
             SplitViewController::RIGHT);
@@ -370,7 +376,8 @@
   // Now close the other snapped window.
   window2.reset();
   EXPECT_EQ(split_view_controller()->InSplitViewMode(), false);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kNoSnap);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kNoSnap);
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
 
   // 3 - Then test the scenario with more than two windows.
@@ -381,14 +388,16 @@
   split_view_controller()->SnapWindow(window4.get(),
                                       SplitViewController::RIGHT);
   EXPECT_EQ(split_view_controller()->InSplitViewMode(), true);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(split_view_controller()->default_snap_position(),
             SplitViewController::LEFT);
 
   // Close one of the snapped windows.
   window4.reset();
   EXPECT_EQ(split_view_controller()->InSplitViewMode(), true);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_EQ(split_view_controller()->default_snap_position(),
             SplitViewController::LEFT);
   // Now overview window grid can be opened.
@@ -397,7 +406,8 @@
   // Close the other snapped window.
   window3.reset();
   EXPECT_EQ(split_view_controller()->InSplitViewMode(), false);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kNoSnap);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kNoSnap);
   // Test the overview winow grid should still open.
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
 }
@@ -426,14 +436,16 @@
   split_view_controller()->SnapWindow(window2.get(),
                                       SplitViewController::RIGHT);
   EXPECT_EQ(split_view_controller()->InSplitViewMode(), true);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(split_view_controller()->default_snap_position(),
             SplitViewController::LEFT);
 
   // Minimizing one of the two snapped windows will not end split view mode.
   WindowState::Get(window1.get())->OnWMEvent(&minimize_event);
   EXPECT_EQ(split_view_controller()->InSplitViewMode(), true);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kRightSnapped);
   // Since left window was minimized, its default snap position changed to
   // RIGHT.
   EXPECT_EQ(split_view_controller()->default_snap_position(),
@@ -444,7 +456,8 @@
   // Now minimize the other snapped window.
   WindowState::Get(window2.get())->OnWMEvent(&minimize_event);
   EXPECT_EQ(split_view_controller()->InSplitViewMode(), false);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kNoSnap);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kNoSnap);
   // The overview window grid is still open.
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
 }
@@ -532,15 +545,18 @@
   split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
   EXPECT_EQ(split_view_controller()->InSplitViewMode(), true);
   EXPECT_EQ(split_view_controller()->left_window(), window1.get());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
 
   wm::ActivateWindow(window2.get());
   EXPECT_EQ(split_view_controller()->right_window(), window2.get());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
 
   wm::ActivateWindow(window3.get());
   EXPECT_EQ(split_view_controller()->right_window(), window3.get());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
 }
 
 // Tests that if split view mode and overview mode are active at the same time,
@@ -559,14 +575,16 @@
 
   split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
   EXPECT_EQ(split_view_controller()->InSplitViewMode(), true);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window1.get());
   // Activate |window1| in preparation to verify that it stays active when
   // overview mode is ended.
   wm::ActivateWindow(window1.get());
 
   ToggleOverview();
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(split_view_controller()->right_window(), window3.get());
   EXPECT_TRUE(wm::IsActiveWindow(window1.get()));
   CheckOverviewEnterExitHistogram("ExitInSplitView", {1, 0}, {0, 1});
@@ -584,12 +602,14 @@
   split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
   split_view_controller()->SnapWindow(window2.get(),
                                       SplitViewController::RIGHT);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(split_view_controller()->GetDefaultSnappedWindow(), window1.get());
 
   ToggleOverview();
   CheckOverviewEnterExitHistogram("EnterInSplitView", {0, 1}, {0, 0});
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_FALSE(
       base::Contains(GetWindowsInOverviewGrids(),
                      split_view_controller()->GetDefaultSnappedWindow()));
@@ -1784,19 +1804,22 @@
   split_view_controller()->SnapWindow(window2.get(),
                                       SplitViewController::RIGHT);
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
 
   // Now lock the screen.
   GetSessionControllerClient()->LockScreen();
   // Change display configuration. Split view mode is still active.
   UpdateDisplay("400x800");
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
 
   // Now unlock the screen.
   GetSessionControllerClient()->UnlockScreen();
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
 }
 
 // Test that when split view and overview are both active when a new window is
@@ -1807,7 +1830,8 @@
 
   split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
   ToggleOverview();
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
 
   // Now new a window. Test it won't end the overview mode
@@ -2202,17 +2226,20 @@
                                       SplitViewController::LEFT);
   split_view_controller()->SnapWindow(normal_window.get(),
                                       SplitViewController::RIGHT);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow,
             always_on_top_window->GetProperty(aura::client::kZOrderingKey));
 
   wm::ActivateWindow(always_on_top_window.get());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow,
             always_on_top_window->GetProperty(aura::client::kZOrderingKey));
 
   wm::ActivateWindow(normal_window.get());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(ui::ZOrderLevel::kFloatingWindow,
             always_on_top_window->GetProperty(aura::client::kZOrderingKey));
 }
@@ -2832,7 +2859,8 @@
   CompleteDrag(std::move(resizer));
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   EXPECT_EQ(split_view_controller()->left_window(), window1.get());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
 
   // Maximize the snapped window to end split view mode and overview mode.
@@ -2897,7 +2925,8 @@
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   EXPECT_EQ(split_view_controller()->left_window(), window1.get());
   EXPECT_EQ(split_view_controller()->right_window(), window2.get());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
   EXPECT_TRUE(window1->GetProperty(kCanAttachToAnotherWindowKey));
   EXPECT_EQ(window1.get(), window_util::GetActiveWindow());
@@ -2967,7 +2996,8 @@
   split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
   split_view_controller()->SnapWindow(window2.get(),
                                       SplitViewController::RIGHT);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window1.get());
   EXPECT_EQ(split_view_controller()->right_window(), window2.get());
 
@@ -2976,7 +3006,8 @@
       StartDrag(window1.get(), window1.get());
   ASSERT_TRUE(resizer.get());
   EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kNone);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kRightSnapped);
   // In this case overview grid will be opened, containing |window3|.
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   OverviewSession* overview_session =
@@ -2991,7 +3022,8 @@
   // be put back to its original position. Overview mode will be ended.
   DragWindowWithOffset(resizer.get(), 10, 10);
   CompleteDrag(std::move(resizer));
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window1.get());
   EXPECT_EQ(split_view_controller()->right_window(), window2.get());
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
@@ -3009,7 +3041,8 @@
   CheckOverviewEnterExitHistogram("EnterInSplitViewByDrag2", {0, 0}, {0, 1});
 
   CompleteDrag(std::move(resizer));
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kRightSnapped);
   EXPECT_EQ(split_view_controller()->right_window(), window1.get());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   overview_session = Shell::Get()->overview_controller()->overview_session();
@@ -3020,13 +3053,15 @@
   CheckOverviewEnterExitHistogram("DoNotExitInSplitViewByDrag", {0, 0}, {0, 1});
   // Snap |window2| again to test 1.c.
   split_view_controller()->SnapWindow(window2.get(), SplitViewController::LEFT);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   CheckOverviewEnterExitHistogram("ExitInSplitViewBySnap", {0, 0}, {0, 2});
 
   // 1.c. If the dragged window is destroyed during dragging (may happen due to
   // all its tabs are attached into another window), nothing changes.
   resizer = StartDrag(window1.get(), window1.get());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   ASSERT_TRUE(resizer.get());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   CheckOverviewEnterExitHistogram("EnterInSplitViewByDrag3", {0, 0}, {0, 2});
@@ -3034,7 +3069,8 @@
   resizer->CompleteDrag();
   resizer.reset();
   window1.reset();
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   // Still in overview.
   CheckOverviewEnterExitHistogram("DoNotExitInSplitViewByDrag3", {0, 0},
@@ -3044,7 +3080,8 @@
   window1.reset(CreateWindowWithType(bounds, AppType::BROWSER));
   split_view_controller()->SnapWindow(window1.get(),
                                       SplitViewController::RIGHT);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window2.get());
   EXPECT_EQ(split_view_controller()->right_window(), window1.get());
   CheckOverviewEnterExitHistogram("ExitInSplitViewBySnap2", {0, 0}, {0, 3});
@@ -3054,7 +3091,8 @@
   // |window2|.
   resizer = StartDrag(window3.get(), window2.get());
   ASSERT_TRUE(resizer.get());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window2.get());
   EXPECT_EQ(split_view_controller()->right_window(), window1.get());
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
@@ -3080,7 +3118,8 @@
             split_view_controller()->GetSnappedWindowBoundsInScreen(
                 window2.get(), SplitViewController::LEFT));
   CompleteDrag(std::move(resizer));
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window3.get());
   EXPECT_EQ(split_view_controller()->right_window(), window1.get());
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
@@ -3091,7 +3130,8 @@
   // the split window.
   resizer = StartDrag(window2.get(), window1.get());
   ASSERT_TRUE(resizer.get());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window3.get());
   EXPECT_EQ(split_view_controller()->right_window(), window1.get());
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
@@ -3106,7 +3146,8 @@
                                   {0, 3});
 
   CompleteDrag(std::move(resizer));
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window2.get());
   EXPECT_EQ(split_view_controller()->right_window(), window1.get());
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
@@ -3133,7 +3174,8 @@
                                       SplitViewController::RIGHT);
   ToggleOverview();
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window1.get());
   CheckOverviewEnterExitHistogram("EnterInSplitView", {0, 1}, {0, 0});
 
@@ -3180,7 +3222,8 @@
   DragWindowTo(resizer.get(), gfx::Point(0, 300));
   EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kPreviewAreaLeft);
   CompleteDrag(std::move(resizer));
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window1.get());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   OverviewSession* overview_session =
@@ -3221,7 +3264,8 @@
   // Preview window shows up on overview side of screen.
   EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kPreviewAreaLeft);
   CompleteDrag(std::move(resizer));
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window2.get());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   overview_session = Shell::Get()->overview_controller()->overview_session();
@@ -3241,7 +3285,8 @@
   EXPECT_EQ(GetIndicatorState(resizer.get()),
             IndicatorState::kPreviewAreaRight);
   CompleteDrag(std::move(resizer));
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_EQ(split_view_controller()->left_window(), window2.get());
   EXPECT_EQ(split_view_controller()->right_window(), window1.get());
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
@@ -3263,7 +3308,8 @@
   split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
   split_view_controller()->SnapWindow(window2.get(),
                                       SplitViewController::RIGHT);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
 
   // Now drags |window1|.
@@ -3271,7 +3317,8 @@
       StartDrag(window1.get(), window1.get());
   // Overview should have been opened.
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kRightSnapped);
 
   // Test that the new window item widget shows up as the first one of the
   // windows in the grid.
@@ -3296,7 +3343,8 @@
   CompleteDrag(std::move(resizer));
 
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kRightSnapped);
   // Test that the dragged window has been added to the overview mode, and it is
   // added at the front of the grid.
   EXPECT_EQ(current_grid->window_list().size(), 2u);
@@ -3348,13 +3396,15 @@
   // Overview should have been opened behind the dragged window.
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   // Split view should still be active.
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kRightSnapped);
   // The value should be properly initialized.
   EXPECT_TRUE(overview_observer->overview_animate_when_exiting());
 
   CompleteDrag(std::move(resizer));
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_FALSE(overview_observer->overview_animate_when_exiting());
 }
 
@@ -3463,19 +3513,22 @@
   EXPECT_FALSE(drop_target_widget->IsVisible());
 
   CompleteDrag(std::move(resizer));
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kRightSnapped);
   EXPECT_TRUE(selector_controller->InOverviewSession());
 
   // Snap another window should end overview.
   split_view_controller()->SnapWindow(window2.get(), SplitViewController::LEFT);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_FALSE(selector_controller->InOverviewSession());
 
   // Now drag |window1| again. Overview and splitview should be both active at
   // the same time during dragging.
   resizer = StartDrag(window1.get(), window1.get());
   EXPECT_TRUE(selector_controller->InOverviewSession());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
 
   current_grid = selector_controller->overview_session()->GetGridWithRootWindow(
       window1->GetRootWindow());
@@ -3654,7 +3707,8 @@
   EXPECT_EQ(IndicatorState::kPreviewAreaLeft, GetIndicatorState(resizer.get()));
   CompleteDrag(std::move(resizer));
   EXPECT_TRUE(WindowState::Get(browser_window1.get())->IsSnapped());
-  EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller()->state());
 
   // Should not consider the drag position if splitview is active. Window should
   // still back to be snapped.
@@ -3662,13 +3716,15 @@
       CreateWindowWithType(bounds, AppType::BROWSER));
   split_view_controller()->SnapWindow(browser_window2.get(),
                                       SplitViewController::RIGHT);
-  EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller()->state());
   resizer = StartDrag(browser_window1.get(), browser_window1.get());
   drop_target_bounds = GetDropTargetBoundsDuringDrag(browser_window1.get());
   DragWindowTo(resizer.get(), gfx::Point(0, drop_target_bounds.y() + 10));
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   CompleteDrag(std::move(resizer));
-  EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller()->state());
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
   EndSplitView();
   EXPECT_FALSE(split_view_controller()->InSplitViewMode());
@@ -3812,7 +3868,8 @@
   EXPECT_TRUE(selector_controller->InOverviewSession());
   EXPECT_TRUE(selector_controller->overview_session()->IsWindowInOverview(
       window2.get()));
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_TRUE(window_state2->IsSnapped());
 
   // Drags |window1| by a small distance. Both splitview and overview should be
@@ -3942,7 +3999,8 @@
                                          drop_target_bounds.y() + 5));
   EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kPreviewAreaLeft);
   CompleteDrag(std::move(resizer));
-  EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller()->state());
 }
 
 // Tests that if a fling event happens on a tab, the tab might or might not
@@ -4038,7 +4096,8 @@
   CompleteDrag(std::move(resizer));
   EXPECT_EQ(window1->bounds(), snapped_bounds1);
   EXPECT_EQ(window2->bounds(), snapped_bounds2);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
 
   // 4. If splitview is active and the dragged window is not the source window.
   resizer = StartDrag(window3.get(), window1.get());
@@ -4051,7 +4110,8 @@
   DragWindowTo(resizer.get(), gfx::Point(100, 200));
   EXPECT_EQ(window1->bounds(), snapped_bounds1);
   EXPECT_EQ(window2->bounds(), snapped_bounds2);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
 
   CompleteDrag(std::move(resizer));
   // In this case |window3| is supposed to merge back its source window
@@ -4060,7 +4120,8 @@
   EXPECT_EQ(window2->bounds(), snapped_bounds2);
   EXPECT_TRUE(window1->GetProperty(kIsDeferredTabDraggingTargetWindowKey));
   window1->ClearProperty(kIsDeferredTabDraggingTargetWindowKey);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
 
   // b). Drag the window far enough so that the dragged window doesn't merge
   // back into its source window.
@@ -4113,13 +4174,15 @@
   split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT);
   ToggleOverview();
   EXPECT_EQ(split_view_controller()->InSplitViewMode(), true);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
 
   std::unique_ptr<aura::Window> dragged_window(
       CreateWindowWithType(bounds, AppType::BROWSER));
   EXPECT_EQ(split_view_controller()->InSplitViewMode(), true);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
 
   std::unique_ptr<WindowResizer> resizer =
@@ -4134,7 +4197,8 @@
   wm::ActivateWindow(dragged_window.get());
   SetIsInTabDragging(resizer->GetTarget(), /*is_dragging=*/false);
 
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
   EXPECT_NE(ui::ZOrderLevel::kNormal,
             split_view_divider()->divider_widget()->GetZOrderLevel());
@@ -4152,14 +4216,16 @@
                                       SplitViewController::LEFT);
   split_view_controller()->SnapWindow(another_window.get(),
                                       SplitViewController::RIGHT);
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
 
   // If the dragged window stays as a separate window after drag ends:
   std::unique_ptr<WindowResizer> resizer =
       StartDrag(dragged_window.get(), dragged_window.get());
   DragWindowWithOffset(resizer.get(), 10, 10);
   CompleteDrag(std::move(resizer));
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kBothSnapped);
   EXPECT_NE(ui::ZOrderLevel::kNormal,
             split_view_divider()->divider_widget()->GetZOrderLevel());
 
@@ -4169,7 +4235,8 @@
   resizer->CompleteDrag();
   resizer.reset();
   dragged_window.reset();
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kRightSnapped);
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   EXPECT_NE(ui::ZOrderLevel::kNormal,
             split_view_divider()->divider_widget()->GetZOrderLevel());
@@ -4409,7 +4476,8 @@
   EXPECT_TRUE(overview_controller->InOverviewSession());
   EXPECT_TRUE(split_view_controller()->InSplitViewMode());
   EXPECT_EQ(split_view_controller()->left_window(), window());
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_TRUE(WindowState::Get(window())->IsSnapped());
 
   // FLING the window with small velocity (smaller than
@@ -4496,7 +4564,8 @@
   // Shelf should be shown during drag.
   EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState());
   EndScrollSequence();
-  EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped);
+  EXPECT_EQ(split_view_controller()->state(),
+            SplitViewController::State::kLeftSnapped);
   EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState());
   // Shelf should be shown after drag and snapped window should be covered by
   // the auto-hide-shown shelf.
@@ -4588,7 +4657,8 @@
   SendScrollStartAndUpdate(location);
   Fling(location, /*velocity_y=*/0, /*velocity_x=*/-large_velocity);
   EXPECT_TRUE(WindowState::Get(window())->IsSnapped());
-  EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller()->state());
 
   // Fling the window in left snapping area to right should drop the window
   // into overview.
@@ -4597,7 +4667,8 @@
   OverviewController* selector_controller = Shell::Get()->overview_controller();
   EXPECT_TRUE(
       selector_controller->overview_session()->IsWindowInOverview(window()));
-  EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kRightSnapped,
+            split_view_controller()->state());
   EXPECT_TRUE(IsTabletMode());
   ToggleOverview();
   EXPECT_TRUE(IsTabletMode());
@@ -4605,69 +4676,81 @@
   // If the window is to the left of the divider but outside the left snapping
   // area, then flinging to the left should drop the window into overview (like
   // just ending the drag).
-  EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller()->state());
   location.set_x(display_bounds.CenterPoint().x() - 10);
   SendScrollStartAndUpdate(location);
   Fling(location, /*velocity_y=*/0, /*velocity_x=*/-large_velocity);
   EXPECT_TRUE(
       selector_controller->overview_session()->IsWindowInOverview(window()));
-  EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kRightSnapped,
+            split_view_controller()->state());
   ToggleOverview();
 
   // If the window is to the left of the divider but outside the left snapping
   // area, then flinging to the right should drop the window into overview (like
   // just ending the drag).
-  EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller()->state());
   SendScrollStartAndUpdate(location);
   Fling(location, /*velocity_y=*/0, /*velocity_x=*/large_velocity);
   EXPECT_TRUE(
       selector_controller->overview_session()->IsWindowInOverview(window()));
-  EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kRightSnapped,
+            split_view_controller()->state());
   ToggleOverview();
 
   // If the window is to the right of the divider but outside the right snapping
   // area, then flinging to the left should drop the window into overview (like
   // just ending the drag).
-  EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller()->state());
   location.set_x(display_bounds.CenterPoint().x() + 10);
   SendScrollStartAndUpdate(location);
   Fling(location, /*velocity_y=*/0, /*velocity_x=*/-large_velocity);
   EXPECT_TRUE(
       selector_controller->overview_session()->IsWindowInOverview(window()));
-  EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kRightSnapped,
+            split_view_controller()->state());
   ToggleOverview();
 
   // If the window is to the right of the divider but outside the right snapping
   // area, then flinging to the right should drop the window into overview (like
   // just ending the drag).
-  EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller()->state());
   SendScrollStartAndUpdate(location);
   Fling(location, /*velocity_y=*/0, /*velocity_x=*/large_velocity);
   EXPECT_TRUE(
       selector_controller->overview_session()->IsWindowInOverview(window()));
-  EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kRightSnapped,
+            split_view_controller()->state());
   ToggleOverview();
 
   // Fling the window in right snapping area to left should drop the window into
   // overview.
-  EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller()->state());
   location.set_x(display_bounds.right() - 1);
   SendScrollStartAndUpdate(location);
   Fling(location, /*velocity_y=*/0, /*velocity_x=*/-large_velocity);
   EXPECT_TRUE(
       selector_controller->overview_session()->IsWindowInOverview(window()));
-  EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kRightSnapped,
+            split_view_controller()->state());
   ToggleOverview();
 
   // Fling the window in right snapping area to right should snap the window to
   // right side.
-  EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller()->state());
   SendScrollStartAndUpdate(location);
   Fling(location, /*velocity_y=*/0, /*velocity_x=*/large_velocity);
   EXPECT_EQ(split_view_controller()->right_window(), window());
   EXPECT_TRUE(selector_controller->overview_session()->IsWindowInOverview(
       window2.get()));
-  EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller()->state());
+  EXPECT_EQ(SplitViewController::State::kRightSnapped,
+            split_view_controller()->state());
 }
 
 // Tests the backdrop bounds during window drag.
diff --git a/ash/wm/splitview/split_view_divider.cc b/ash/wm/splitview/split_view_divider.cc
index 0d96a2f2..a40739b 100644
--- a/ash/wm/splitview/split_view_divider.cc
+++ b/ash/wm/splitview/split_view_divider.cc
@@ -343,9 +343,12 @@
 void SplitViewDivider::OnWindowDragStarted(aura::Window* dragged_window) {
   is_dragging_window_ = true;
   SetAlwaysOnTop(false);
-  // Make sure |divider_widget_| is placed below the dragged window.
-  dragged_window->parent()->StackChildBelow(divider_widget_->GetNativeWindow(),
-                                            dragged_window);
+
+  aura::Window* divider_window = divider_widget_->GetNativeWindow();
+  // If |divider_window| and |dragged_window| are siblings, then make sure that
+  // |divider_window| is stacked below |dragged_window|.
+  if (divider_window->parent() == dragged_window->parent())
+    divider_window->parent()->StackChildBelow(divider_window, dragged_window);
 }
 
 void SplitViewDivider::OnWindowDragEnded() {
diff --git a/ash/wm/splitview/split_view_drag_indicators_unittest.cc b/ash/wm/splitview/split_view_drag_indicators_unittest.cc
index 0bd24c0..ea2f071a 100644
--- a/ash/wm/splitview/split_view_drag_indicators_unittest.cc
+++ b/ash/wm/splitview/split_view_drag_indicators_unittest.cc
@@ -316,7 +316,8 @@
   // Snap window to the left.
   overview_session_->CompleteDrag(item, gfx::PointF(edge_inset, y_position));
   ASSERT_TRUE(split_view_controller()->InSplitViewMode());
-  ASSERT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state());
+  ASSERT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller()->state());
 
   // Verify that when there is a left snapped window, dragging an item to the
   // right will show the right preview area.
diff --git a/ash/wm/splitview/split_view_observer.h b/ash/wm/splitview/split_view_observer.h
new file mode 100644
index 0000000..629c17d
--- /dev/null
+++ b/ash/wm/splitview/split_view_observer.h
@@ -0,0 +1,30 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef ASH_WM_SPLITVIEW_SPLIT_VIEW_OBSERVER_H_
+#define ASH_WM_SPLITVIEW_SPLIT_VIEW_OBSERVER_H_
+
+#include "ash/ash_export.h"
+#include "ash/wm/splitview/split_view_controller.h"
+
+namespace ash {
+
+class ASH_EXPORT SplitViewObserver {
+ public:
+  // Called when split view state changed from |previous_state| to |state|.
+  virtual void OnSplitViewStateChanged(
+      SplitViewController::State previous_state,
+      SplitViewController::State state) {}
+
+  // Called when split view divider's position has changed.
+  virtual void OnSplitViewDividerPositionChanged() {}
+
+ protected:
+  SplitViewObserver() = default;
+  virtual ~SplitViewObserver() = default;
+};
+
+}  // namespace ash
+
+#endif  // ASH_WM_SPLITVIEW_SPLIT_VIEW_OBSERVER_H_
diff --git a/ash/wm/splitview/split_view_utils.cc b/ash/wm/splitview/split_view_utils.cc
index f8341fe..74880fa 100644
--- a/ash/wm/splitview/split_view_utils.cc
+++ b/ash/wm/splitview/split_view_utils.cc
@@ -269,7 +269,8 @@
           break;
       }
 
-      if (split_view_controller->state() == SplitViewState::kBothSnapped)
+      if (split_view_controller->state() ==
+          SplitViewController::State::kBothSnapped)
         break;
     }
   }
@@ -277,9 +278,9 @@
   // Ensure that overview mode is active if and only if there is a window
   // snapped to one side but no window snapped to the other side.
   OverviewController* overview_controller = Shell::Get()->overview_controller();
-  SplitViewState state = split_view_controller->state();
-  if (state == SplitViewState::kLeftSnapped ||
-      state == SplitViewState::kRightSnapped) {
+  SplitViewController::State state = split_view_controller->state();
+  if (state == SplitViewController::State::kLeftSnapped ||
+      state == SplitViewController::State::kRightSnapped) {
     overview_controller->StartOverview();
   } else {
     overview_controller->EndOverview();
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.cc b/ash/wm/tablet_mode/tablet_mode_controller.cc
index 4a511d6..25ff9b2 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller.cc
@@ -1018,8 +1018,8 @@
   // side, then overview mode should be started (to be seen on the side with
   // no snapped window).
   const auto state = Shell::Get()->split_view_controller()->state();
-  if (state == SplitViewState::kLeftSnapped ||
-      state == SplitViewState::kRightSnapped) {
+  if (state == SplitViewController::State::kLeftSnapped ||
+      state == SplitViewController::State::kRightSnapped) {
     Shell::Get()->overview_controller()->StartOverview();
   }
 
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
index 9eb15fba..acc57adf 100644
--- a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
+++ b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
@@ -1141,7 +1141,8 @@
       Shell::Get()->split_view_controller();
   std::unique_ptr<aura::Window> window = CreateTestWindow();
   tablet_mode_controller()->SetEnabledForTest(true);
-  EXPECT_EQ(SplitViewState::kNoSnap, split_view_controller->state());
+  EXPECT_EQ(SplitViewController::State::kNoSnap,
+            split_view_controller->state());
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
 }
 
@@ -1152,7 +1153,8 @@
       Shell::Get()->split_view_controller();
   std::unique_ptr<aura::Window> window = CreateDesktopWindowSnappedLeft();
   tablet_mode_controller()->SetEnabledForTest(true);
-  EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
+  EXPECT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller->state());
   EXPECT_EQ(window.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   EXPECT_EQ(window.get(), window_util::GetActiveWindow());
@@ -1165,7 +1167,8 @@
       Shell::Get()->split_view_controller();
   std::unique_ptr<aura::Window> window = CreateDesktopWindowSnappedRight();
   tablet_mode_controller()->SetEnabledForTest(true);
-  EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller->state());
+  EXPECT_EQ(SplitViewController::State::kRightSnapped,
+            split_view_controller->state());
   EXPECT_EQ(window.get(), split_view_controller->right_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   EXPECT_EQ(window.get(), window_util::GetActiveWindow());
@@ -1182,7 +1185,8 @@
       CreateDesktopWindowSnappedRight();
   wm::ActivateWindow(left_window.get());
   tablet_mode_controller()->SetEnabledForTest(true);
-  EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller->state());
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller->state());
   EXPECT_EQ(left_window.get(), split_view_controller->left_window());
   EXPECT_EQ(right_window.get(), split_view_controller->right_window());
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
@@ -1200,7 +1204,8 @@
       CreateDesktopWindowSnappedRight();
   ASSERT_EQ(right_window.get(), window_util::GetActiveWindow());
   tablet_mode_controller()->SetEnabledForTest(true);
-  EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller->state());
+  EXPECT_EQ(SplitViewController::State::kBothSnapped,
+            split_view_controller->state());
   EXPECT_EQ(left_window.get(), split_view_controller->left_window());
   EXPECT_EQ(right_window.get(), split_view_controller->right_window());
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
@@ -1221,7 +1226,8 @@
       CreateDesktopWindowSnappedRight();
   wm::ActivateWindow(left_window.get());
   tablet_mode_controller()->SetEnabledForTest(true);
-  EXPECT_EQ(SplitViewState::kNoSnap, split_view_controller->state());
+  EXPECT_EQ(SplitViewController::State::kNoSnap,
+            split_view_controller->state());
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
 }
 
@@ -1243,7 +1249,8 @@
   wm::ActivateWindow(right_window.get());
   wm::ActivateWindow(left_window.get());
   tablet_mode_controller()->SetEnabledForTest(true);
-  EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
+  EXPECT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller->state());
   EXPECT_EQ(left_window.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   EXPECT_EQ(left_window.get(), window_util::GetActiveWindow());
@@ -1261,7 +1268,8 @@
   ::wm::AddTransientChild(parent.get(), child.get());
   wm::ActivateWindow(child.get());
   tablet_mode_controller()->SetEnabledForTest(true);
-  EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
+  EXPECT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller->state());
   EXPECT_EQ(parent.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   EXPECT_EQ(child.get(), window_util::GetActiveWindow());
@@ -1278,7 +1286,8 @@
   ASSERT_TRUE(wm::IsActiveWindow(
       GetAppListTestHelper()->GetAppListView()->GetWidget()->GetNativeView()));
   tablet_mode_controller()->SetEnabledForTest(true);
-  EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
+  EXPECT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller->state());
   EXPECT_EQ(window.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   EXPECT_EQ(window.get(), window_util::GetActiveWindow());
@@ -1298,7 +1307,8 @@
       dragged_window.get(), gfx::Point(), HTCAPTION,
       ash::ToplevelWindowEventHandler::EndClosure()));
   tablet_mode_controller()->SetEnabledForTest(true);
-  EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
+  EXPECT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller->state());
   EXPECT_EQ(snapped_window.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   EXPECT_EQ(snapped_window.get(), window_util::GetActiveWindow());
@@ -1318,7 +1328,8 @@
       CreateDesktopWindowSnappedLeft();
   wm::ActivateWindow(window_hidden_from_overview.get());
   tablet_mode_controller()->SetEnabledForTest(true);
-  EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
+  EXPECT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller->state());
   EXPECT_EQ(snapped_window.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   EXPECT_EQ(snapped_window.get(), window_util::GetActiveWindow());
@@ -1342,7 +1353,8 @@
       dragged_window.get(), gfx::Point(), HTCAPTION,
       ash::ToplevelWindowEventHandler::EndClosure()));
   tablet_mode_controller()->SetEnabledForTest(true);
-  EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
+  EXPECT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller->state());
   EXPECT_EQ(parent.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   EXPECT_EQ(parent.get(), window_util::GetActiveWindow());
@@ -1372,7 +1384,8 @@
       CreateDesktopWindowSnappedRight();
   wm::ActivateWindow(left_window.get());
   tablet_mode_controller()->SetEnabledForTest(true);
-  EXPECT_EQ(SplitViewState::kNoSnap, split_view_controller->state());
+  EXPECT_EQ(SplitViewController::State::kNoSnap,
+            split_view_controller->state());
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
 }
 
@@ -1401,7 +1414,8 @@
   right_window_state->OnWMEvent(&snap_to_right);
   wm::ActivateWindow(right_window.get());
   tablet_mode_controller()->SetEnabledForTest(true);
-  EXPECT_EQ(SplitViewState::kNoSnap, split_view_controller->state());
+  EXPECT_EQ(SplitViewController::State::kNoSnap,
+            split_view_controller->state());
   EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession());
 }
 
@@ -1431,7 +1445,8 @@
   right_window_state->OnWMEvent(&snap_to_right);
   ASSERT_EQ(left_window.get(), window_util::GetActiveWindow());
   tablet_mode_controller()->SetEnabledForTest(true);
-  EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
+  EXPECT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller->state());
   EXPECT_EQ(left_window.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   EXPECT_EQ(left_window.get(), window_util::GetActiveWindow());
@@ -1462,7 +1477,8 @@
       CreateDesktopWindowSnappedRight();
   ASSERT_EQ(right_window.get(), window_util::GetActiveWindow());
   tablet_mode_controller()->SetEnabledForTest(true);
-  EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller->state());
+  EXPECT_EQ(SplitViewController::State::kRightSnapped,
+            split_view_controller->state());
   EXPECT_EQ(right_window.get(), split_view_controller->right_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   EXPECT_EQ(right_window.get(), window_util::GetActiveWindow());
@@ -1490,7 +1506,8 @@
   std::unique_ptr<aura::Window> window2 = CreateDesktopWindowSnappedLeft();
   wm::ActivateWindow(window1.get());
   tablet_mode_controller()->SetEnabledForTest(true);
-  EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state());
+  EXPECT_EQ(SplitViewController::State::kLeftSnapped,
+            split_view_controller->state());
   EXPECT_EQ(window1.get(), split_view_controller->left_window());
   EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession());
   EXPECT_EQ(window1.get(), window_util::GetActiveWindow());
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager.cc b/ash/wm/tablet_mode/tablet_mode_window_manager.cc
index ca59421..8ff0ac89 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_manager.cc
+++ b/ash/wm/tablet_mode/tablet_mode_window_manager.cc
@@ -379,9 +379,9 @@
 }
 
 void TabletModeWindowManager::OnSplitViewStateChanged(
-    SplitViewState previous_state,
-    SplitViewState state) {
-  if (state != SplitViewState::kNoSnap)
+    SplitViewController::State previous_state,
+    SplitViewController::State state) {
+  if (state != SplitViewController::State::kNoSnap)
     return;
   switch (Shell::Get()->split_view_controller()->end_reason()) {
     case SplitViewController::EndReason::kNormal:
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager.h b/ash/wm/tablet_mode/tablet_mode_window_manager.h
index af72897..0e8dba5 100644
--- a/ash/wm/tablet_mode/tablet_mode_window_manager.h
+++ b/ash/wm/tablet_mode/tablet_mode_window_manager.h
@@ -12,11 +12,11 @@
 #include <vector>
 
 #include "ash/ash_export.h"
-#include "ash/public/cpp/split_view.h"
 #include "ash/session/session_observer.h"
 #include "ash/wm/mru_window_tracker.h"
 #include "ash/wm/overview/overview_observer.h"
 #include "ash/wm/splitview/split_view_controller.h"
+#include "ash/wm/splitview/split_view_observer.h"
 #include "base/containers/flat_set.h"
 #include "base/macros.h"
 #include "ui/aura/window_observer.h"
@@ -83,8 +83,8 @@
   void OnOverviewModeEndingAnimationComplete(bool canceled) override;
 
   // SplitViewObserver:
-  void OnSplitViewStateChanged(SplitViewState previous_state,
-                               SplitViewState state) override;
+  void OnSplitViewStateChanged(SplitViewController::State previous_state,
+                               SplitViewController::State state) override;
 
   // aura::WindowObserver:
   void OnWindowDestroying(aura::Window* window) override;
diff --git a/ash/wm/workspace/backdrop_controller.cc b/ash/wm/workspace/backdrop_controller.cc
index d8e4568..5682c74 100644
--- a/ash/wm/workspace/backdrop_controller.cc
+++ b/ash/wm/workspace/backdrop_controller.cc
@@ -231,8 +231,9 @@
   UpdateBackdrop();
 }
 
-void BackdropController::OnSplitViewStateChanged(SplitViewState previous_state,
-                                                 SplitViewState state) {
+void BackdropController::OnSplitViewStateChanged(
+    SplitViewController::State previous_state,
+    SplitViewController::State state) {
   // Force the update of the backdrop, even if overview is active, so that the
   // backdrop shows up properly in the mini_views.
   UpdateBackdropInternal();
@@ -429,10 +430,10 @@
   aura::Window* window = GetTopmostWindowWithBackdrop();
   SplitViewController* split_view_controller =
       Shell::Get()->split_view_controller();
-  SplitViewState state = split_view_controller->state();
-  if ((state == SplitViewState::kLeftSnapped &&
+  SplitViewController::State state = split_view_controller->state();
+  if ((state == SplitViewController::State::kLeftSnapped &&
        window == split_view_controller->left_window()) ||
-      (state == SplitViewState::kRightSnapped &&
+      (state == SplitViewController::State::kRightSnapped &&
        window == split_view_controller->right_window())) {
     return false;
   }
@@ -445,14 +446,15 @@
 
   SplitViewController* split_view_controller =
       Shell::Get()->split_view_controller();
-  SplitViewState state = split_view_controller->state();
-  DCHECK(state == SplitViewState::kLeftSnapped ||
-         state == SplitViewState::kRightSnapped);
+  SplitViewController::State state = split_view_controller->state();
+  DCHECK(state == SplitViewController::State::kLeftSnapped ||
+         state == SplitViewController::State::kRightSnapped);
   aura::Window* snapped_window =
       split_view_controller->GetDefaultSnappedWindow();
   SplitViewController::SnapPosition snap_position =
-      (state == SplitViewState::kLeftSnapped) ? SplitViewController::LEFT
-                                              : SplitViewController::RIGHT;
+      (state == SplitViewController::State::kLeftSnapped)
+          ? SplitViewController::LEFT
+          : SplitViewController::RIGHT;
   return split_view_controller->GetSnappedWindowBoundsInScreenUnadjusted(
       snapped_window, snap_position);
 }
diff --git a/ash/wm/workspace/backdrop_controller.h b/ash/wm/workspace/backdrop_controller.h
index 9339b898..1190fe0 100644
--- a/ash/wm/workspace/backdrop_controller.h
+++ b/ash/wm/workspace/backdrop_controller.h
@@ -9,10 +9,11 @@
 
 #include "ash/accessibility/accessibility_observer.h"
 #include "ash/ash_export.h"
-#include "ash/public/cpp/split_view.h"
 #include "ash/public/cpp/tablet_mode_observer.h"
 #include "ash/public/cpp/wallpaper_controller_observer.h"
 #include "ash/wm/overview/overview_observer.h"
+#include "ash/wm/splitview/split_view_controller.h"
+#include "ash/wm/splitview/split_view_observer.h"
 #include "base/macros.h"
 #include "ui/gfx/geometry/rect.h"
 
@@ -77,8 +78,8 @@
   void OnAccessibilityStatusChanged() override;
 
   // SplitViewObserver:
-  void OnSplitViewStateChanged(SplitViewState previous_state,
-                               SplitViewState state) override;
+  void OnSplitViewStateChanged(SplitViewController::State previous_state,
+                               SplitViewController::State state) override;
   void OnSplitViewDividerPositionChanged() override;
 
   // WallpaperControllerObserver:
diff --git a/base/fuchsia/scoped_service_binding.h b/base/fuchsia/scoped_service_binding.h
index ea11d02..fe37cbe 100644
--- a/base/fuchsia/scoped_service_binding.h
+++ b/base/fuchsia/scoped_service_binding.h
@@ -152,7 +152,7 @@
                   dispatcher);
   }
 
-  void OnBindingEmpty() {
+  void OnBindingEmpty(zx_status_t status) {
     binding_.set_error_handler(nullptr);
     std::move(on_last_client_callback_).Run();
   }
diff --git a/base/fuchsia/scoped_service_binding_unittest.cc b/base/fuchsia/scoped_service_binding_unittest.cc
index ddbea03..4368055 100644
--- a/base/fuchsia/scoped_service_binding_unittest.cc
+++ b/base/fuchsia/scoped_service_binding_unittest.cc
@@ -106,5 +106,21 @@
   VerifyTestInterface(&release_stub, ZX_ERR_PEER_CLOSED);
 }
 
+TEST_F(ScopedServiceBindingTest, SingleBindingSetOnLastClientCallback) {
+  service_binding_.reset();
+  ScopedSingleClientServiceBinding<testfidl::TestInterface>
+      single_service_binding(outgoing_directory_.get(), &test_service_);
+
+  base::RunLoop run_loop;
+  single_service_binding.SetOnLastClientCallback(run_loop.QuitClosure());
+
+  auto current_client =
+      public_service_directory_->Connect<testfidl::TestInterface>();
+  VerifyTestInterface(&current_client, ZX_OK);
+  current_client.Unbind();
+
+  run_loop.Run();
+}
+
 }  // namespace fuchsia
 }  // namespace base
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 09546bb..28eee09 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -1159,7 +1159,6 @@
     "java/res_template/xml/file_paths.xml",
     "java/res_template/xml/launchershortcuts.xml",
     "java/res_template/xml/searchable.xml",
-    "java/res_template/xml/syncadapter.xml",
   ]
   res_dir = "java/res_template"
   variables = [ "manifest_package=$chrome_public_manifest_package" ]
@@ -1170,7 +1169,6 @@
     "java/res_template/xml/file_paths.xml",
     "java/res_template/xml/launchershortcuts.xml",
     "java/res_template/xml/searchable.xml",
-    "java/res_template/xml/syncadapter.xml",
   ]
   res_dir = "java/res_template"
 
@@ -1705,7 +1703,8 @@
   # of manually-instantiated manifests.
   jinja_template("${target_name}__android_manifest") {
     includes = [ "java/AndroidManifest.xml" ]
-    variables = chrome_public_jinja_variables
+    variables =
+        chrome_public_jinja_variables + [ "include_arcore_manifest_flag=true" ]
     if (_is_trichrome) {
       input = "java/AndroidManifest_trichrome_chrome.xml"
       variables += trichrome_jinja_variables
@@ -1719,7 +1718,6 @@
       variables += monochrome_android_manifest_jinja_variables + [
                      "target_sdk_version=$android_sdk_version",
                      "webview_library=libmonochrome${_arch}.so",
-                     "include_arcore_manifest_flag=true",
                    ]
     }
 
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index 1e64d79..718f01d 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -1708,7 +1708,6 @@
   "java/src/org/chromium/chrome/browser/ui/tablet/emptybackground/EmptyBackgroundViewWrapper.java",
   "java/src/org/chromium/chrome/browser/ui/tablet/emptybackground/incognitotoggle/IncognitoToggleButton.java",
   "java/src/org/chromium/chrome/browser/ui/tablet/emptybackground/incognitotoggle/IncognitoToggleButtonTablet.java",
-  "java/src/org/chromium/chrome/browser/util/AccessibilityUtil.java",
   "java/src/org/chromium/chrome/browser/util/ChromeIntentUtil.java",
   "java/src/org/chromium/chrome/browser/util/ColorUtils.java",
   "java/src/org/chromium/chrome/browser/util/FeatureUtilities.java",
diff --git a/chrome/android/features/autofill_assistant/BUILD.gn b/chrome/android/features/autofill_assistant/BUILD.gn
index 8d630ad5..51b9102 100644
--- a/chrome/android/features/autofill_assistant/BUILD.gn
+++ b/chrome/android/features/autofill_assistant/BUILD.gn
@@ -36,6 +36,7 @@
     "//chrome/android/public/profiles:java",
     "//chrome/browser/image_fetcher:java",
     "//chrome/browser/ui/android/widget:java",
+    "//chrome/browser/util/android:java",
     "//components/policy/android:policy_java",
     "//components/signin/core/browser/android:java",
     "//components/url_formatter/android:url_formatter_java",
diff --git a/chrome/android/feed/OWNERS b/chrome/android/feed/OWNERS
index 7c721bc..27980a9 100644
--- a/chrome/android/feed/OWNERS
+++ b/chrome/android/feed/OWNERS
@@ -1,6 +1,8 @@
+carlosk@chromium.org
 fgorski@chromium.org
+harringtond@chromium.org
 skym@chromium.org
 twellington@chromium.org
 
-# Team: chrome-jardin-team@google.com
+# Team: feed@chromium.org
 # COMPONENT: UI>Browser>ContentSuggestions>Feed
diff --git a/chrome/android/java/AndroidManifest.xml b/chrome/android/java/AndroidManifest.xml
index da7fc8f..c786463 100644
--- a/chrome/android/java/AndroidManifest.xml
+++ b/chrome/android/java/AndroidManifest.xml
@@ -951,16 +951,6 @@
                 android:resource="@xml/file_paths" />
         </provider>
 
-        <!-- Sync adapter for browser invalidation. -->
-        <service android:name="org.chromium.chrome.browser.invalidation.ChromeBrowserSyncAdapterService"
-            android:exported="false">
-            <intent-filter>
-                <action android:name="android.content.SyncAdapter" />
-            </intent-filter>
-            <meta-data android:name="android.content.SyncAdapter"
-                       android:resource="@xml/syncadapter" />
-        </service>
-
         <!-- Broadcast receiver that will be notified of account changes -->
         <receiver android:name="org.chromium.chrome.browser.services.AccountsChangedReceiver">
             <intent-filter>
diff --git a/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected b/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected
index 562b2294..fed3b425 100644
--- a/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected
+++ b/chrome/android/java/monochrome_public_bundle__base_bundle_module.AndroidManifest.expected
@@ -1522,14 +1522,6 @@
         android:name="org.chromium.chrome.browser.incognito.IncognitoNotificationService"/>
     <service
         android:exported="false"
-        android:name="org.chromium.chrome.browser.invalidation.ChromeBrowserSyncAdapterService">
-      <intent-filter>
-        <action android:name="android.content.SyncAdapter"/>
-      </intent-filter>
-      <meta-data android:name="android.content.SyncAdapter" android:resource="@xml/syncadapter"/>
-    </service>
-    <service
-        android:exported="false"
         android:name="org.chromium.chrome.browser.media.MediaCaptureNotificationService"/>
     <service
         android:exported="false"
diff --git a/chrome/android/java/res_template/xml/syncadapter.xml b/chrome/android/java/res_template/xml/syncadapter.xml
deleted file mode 100644
index a0c78f9f..0000000
--- a/chrome/android/java/res_template/xml/syncadapter.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright 2015 The Chromium Authors. All rights reserved.
-     Use of this source code is governed by a BSD-style license that can be
-     found in the LICENSE file. -->
-
-<!-- The attributes in this XML file provide configuration information -->
-<!-- for the SyncAdapter. -->
-
-<sync-adapter xmlns:android="http://schemas.android.com/apk/res/android"
-    android:contentAuthority="{{manifest_package}}"
-    android:accountType="com.google" />
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
index 2d772df..52f8978 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridge.java
@@ -15,6 +15,7 @@
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.NativeMethods;
 import org.chromium.chrome.browser.ChromeActivity;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.profiles.ProfileKey;
@@ -61,8 +62,9 @@
     public static OfflinePageBridge getForProfile(Profile profile) {
         ThreadUtils.assertOnUiThread();
 
-        if (profile == null)
+        if (profile == null) {
             return null;
+        }
 
         return getForProfileKey(profile.getProfileKey());
     }
@@ -77,7 +79,7 @@
     public static OfflinePageBridge getForProfileKey(ProfileKey profileKey) {
         ThreadUtils.assertOnUiThread();
 
-        return nativeGetOfflinePageBridgeForProfileKey(profileKey);
+        return OfflinePageBridgeJni.get().getOfflinePageBridgeForProfileKey(profileKey);
     }
 
     /**
@@ -140,7 +142,7 @@
      * @return True if an offline copy of the given URL can be saved.
      */
     public static boolean canSavePage(String url) {
-        return nativeCanSavePage(url);
+        return OfflinePageBridgeJni.get().canSavePage(url);
     }
 
     /**
@@ -176,7 +178,8 @@
     @VisibleForTesting
     public void getAllPages(final Callback<List<OfflinePageItem>> callback) {
         List<OfflinePageItem> result = new ArrayList<>();
-        nativeGetAllPages(mNativeOfflinePageBridge, result, callback);
+        OfflinePageBridgeJni.get().getAllPages(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, result, callback);
     }
 
     /**
@@ -198,7 +201,8 @@
         }
 
         List<OfflinePageItem> result = new ArrayList<>();
-        nativeGetPagesByClientId(mNativeOfflinePageBridge, result, namespaces, ids, callback);
+        OfflinePageBridgeJni.get().getPagesByClientId(mNativeOfflinePageBridge,
+                OfflinePageBridge.this, result, namespaces, ids, callback);
     }
 
     /**
@@ -209,7 +213,8 @@
      */
     public void getPagesByRequestOrigin(String origin, Callback<List<OfflinePageItem>> callback) {
         List<OfflinePageItem> result = new ArrayList<>();
-        nativeGetPagesByRequestOrigin(mNativeOfflinePageBridge, result, origin, callback);
+        OfflinePageBridgeJni.get().getPagesByRequestOrigin(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, result, origin, callback);
     }
 
     /**
@@ -223,7 +228,8 @@
     public void getPagesByNamespace(
             final String namespace, final Callback<List<OfflinePageItem>> callback) {
         List<OfflinePageItem> result = new ArrayList<>();
-        nativeGetPagesByNamespace(mNativeOfflinePageBridge, result, namespace, callback);
+        OfflinePageBridgeJni.get().getPagesByNamespace(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, result, namespace, callback);
     }
 
     /**
@@ -236,7 +242,8 @@
      */
     public void selectPageForOnlineUrl(String onlineUrl, int tabId,
             Callback<OfflinePageItem> callback) {
-        nativeSelectPageForOnlineUrl(mNativeOfflinePageBridge, onlineUrl, tabId, callback);
+        OfflinePageBridgeJni.get().selectPageForOnlineUrl(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, onlineUrl, tabId, callback);
     }
 
     /**
@@ -247,7 +254,8 @@
      *         pass back <code>null</code> if not.
      */
     public void getPageByOfflineId(final long offlineId, final Callback<OfflinePageItem> callback) {
-        nativeGetPageByOfflineId(mNativeOfflinePageBridge, offlineId, callback);
+        OfflinePageBridgeJni.get().getPageByOfflineId(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, offlineId, callback);
     }
 
     /**
@@ -289,8 +297,9 @@
         assert webContents != null;
         assert origin != null;
 
-        nativeSavePage(mNativeOfflinePageBridge, callback, webContents, clientId.getNamespace(),
-                clientId.getId(), origin.encodeAsJsonString());
+        OfflinePageBridgeJni.get().savePage(mNativeOfflinePageBridge, OfflinePageBridge.this,
+                callback, webContents, clientId.getNamespace(), clientId.getId(),
+                origin.encodeAsJsonString());
     }
 
     /**
@@ -324,7 +333,8 @@
             ids[i] = clientIds.get(i).getId();
         }
 
-        nativeDeletePagesByClientId(mNativeOfflinePageBridge, namespaces, ids, callback);
+        OfflinePageBridgeJni.get().deletePagesByClientId(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, namespaces, ids, callback);
     }
 
     /**
@@ -345,8 +355,8 @@
             ids[i] = clientIds.get(i).getId();
         }
 
-        nativeDeletePagesByClientIdAndOrigin(
-                mNativeOfflinePageBridge, namespaces, ids, origin.encodeAsJsonString(), callback);
+        OfflinePageBridgeJni.get().deletePagesByClientIdAndOrigin(mNativeOfflinePageBridge,
+                OfflinePageBridge.this, namespaces, ids, origin.encodeAsJsonString(), callback);
     }
 
     /**
@@ -369,7 +379,8 @@
         for (int i = 0; i < offlineIdList.size(); i++) {
             offlineIds[i] = offlineIdList.get(i).longValue();
         }
-        nativeDeletePagesByOfflineId(mNativeOfflinePageBridge, offlineIds, callback);
+        OfflinePageBridgeJni.get().deletePagesByOfflineId(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, offlineIds, callback);
     }
 
     /**
@@ -379,8 +390,8 @@
      *         the new path of the file.
      */
     public void publishInternalPageByOfflineId(long offlineId, Callback<String> publishedCallback) {
-        nativePublishInternalPageByOfflineId(
-                mNativeOfflinePageBridge, offlineId, publishedCallback);
+        OfflinePageBridgeJni.get().publishInternalPageByOfflineId(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, offlineId, publishedCallback);
     }
 
     /**
@@ -389,7 +400,8 @@
      * @param publishedCallback Function to call when publishing is done.
      */
     public void publishInternalPageByGuid(String guid, Callback<String> publishedCallback) {
-        nativePublishInternalPageByGuid(mNativeOfflinePageBridge, guid, publishedCallback);
+        OfflinePageBridgeJni.get().publishInternalPageByGuid(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, guid, publishedCallback);
     }
 
     /**
@@ -405,7 +417,8 @@
      * @return The extra request header string.
      */
     public String getOfflinePageHeaderForReload(WebContents webContents) {
-        return nativeGetOfflinePageHeaderForReload(mNativeOfflinePageBridge, webContents);
+        return OfflinePageBridgeJni.get().getOfflinePageHeaderForReload(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, webContents);
     }
 
     /**
@@ -413,7 +426,8 @@
      * @return True if an offline preview is being shown.
      */
     public boolean isShowingOfflinePreview(WebContents webContents) {
-        return nativeIsShowingOfflinePreview(mNativeOfflinePageBridge, webContents);
+        return OfflinePageBridgeJni.get().isShowingOfflinePreview(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, webContents);
     }
 
     /**
@@ -421,12 +435,14 @@
      * @return True if download button is being shown in the error page.
      */
     public boolean isShowingDownloadButtonInErrorPage(WebContents webContents) {
-        return nativeIsShowingDownloadButtonInErrorPage(mNativeOfflinePageBridge, webContents);
+        return OfflinePageBridgeJni.get().isShowingDownloadButtonInErrorPage(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, webContents);
     }
 
     /** Tells the native side that the tab of |webContents| will be closed. */
     void willCloseTab(WebContents webContents) {
-        nativeWillCloseTab(mNativeOfflinePageBridge, webContents);
+        OfflinePageBridgeJni.get().willCloseTab(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, webContents);
     }
 
     /**
@@ -456,7 +472,8 @@
      */
     public void scheduleDownload(WebContents webContents, String nameSpace, String url,
             int uiAction, OfflinePageOrigin origin) {
-        nativeScheduleDownload(mNativeOfflinePageBridge, webContents, nameSpace, url, uiAction,
+        OfflinePageBridgeJni.get().scheduleDownload(mNativeOfflinePageBridge,
+                OfflinePageBridge.this, webContents, nameSpace, url, uiAction,
                 origin.encodeAsJsonString());
     }
 
@@ -466,7 +483,8 @@
      * @return True if the offline page is opened.
      */
     public boolean isOfflinePage(WebContents webContents) {
-        return nativeIsOfflinePage(mNativeOfflinePageBridge, webContents);
+        return OfflinePageBridgeJni.get().isOfflinePage(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, webContents);
     }
 
     /**
@@ -475,7 +493,8 @@
      * @return true if the page is in a temporary namespace.
      */
     public boolean isTemporaryNamespace(String nameSpace) {
-        return nativeIsTemporaryNamespace(mNativeOfflinePageBridge, nameSpace);
+        return OfflinePageBridgeJni.get().isTemporaryNamespace(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, nameSpace);
     }
 
     /**
@@ -484,7 +503,8 @@
      * @return True if the file is in a private directory.
      */
     public boolean isInPrivateDirectory(String filePath) {
-        return nativeIsInPrivateDirectory(mNativeOfflinePageBridge, filePath);
+        return OfflinePageBridgeJni.get().isInPrivateDirectory(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, filePath);
     }
 
     /**
@@ -494,7 +514,8 @@
      */
     @Nullable
     public OfflinePageItem getOfflinePage(WebContents webContents) {
-        return nativeGetOfflinePage(mNativeOfflinePageBridge, webContents);
+        return OfflinePageBridgeJni.get().getOfflinePage(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, webContents);
     }
 
     /**
@@ -506,7 +527,8 @@
      *         if no fresh enough content is found.
      */
     public void checkForNewOfflineContent(long freshnessTimeMillis, Callback<String> callback) {
-        nativeCheckForNewOfflineContent(mNativeOfflinePageBridge, freshnessTimeMillis, callback);
+        OfflinePageBridgeJni.get().checkForNewOfflineContent(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, freshnessTimeMillis, callback);
     }
 
     /**
@@ -521,7 +543,8 @@
      */
     public void getLoadUrlParamsByOfflineId(
             long offlineId, @LaunchLocation int location, Callback<LoadUrlParams> callback) {
-        nativeGetLoadUrlParamsByOfflineId(mNativeOfflinePageBridge, offlineId, location, callback);
+        OfflinePageBridgeJni.get().getLoadUrlParamsByOfflineId(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, offlineId, location, callback);
     }
 
     /**
@@ -532,7 +555,8 @@
      */
     public void getLoadUrlParamsForOpeningMhtmlFileOrContent(
             String url, Callback<LoadUrlParams> callback) {
-        nativeGetLoadUrlParamsForOpeningMhtmlFileOrContent(mNativeOfflinePageBridge, url, callback);
+        OfflinePageBridgeJni.get().getLoadUrlParamsForOpeningMhtmlFileOrContent(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, url, callback);
     }
 
     /**
@@ -541,7 +565,8 @@
      * @return True if a trusted offline page is shown.
      */
     public boolean isShowingTrustedOfflinePage(WebContents webContents) {
-        return nativeIsShowingTrustedOfflinePage(mNativeOfflinePageBridge, webContents);
+        return OfflinePageBridgeJni.get().isShowingTrustedOfflinePage(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, webContents);
     }
 
     /**
@@ -551,7 +576,8 @@
      * @param callback Callback to notify the result.
      */
     public void acquireFileAccessPermission(WebContents webContents, Callback<Boolean> callback) {
-        nativeAcquireFileAccessPermission(mNativeOfflinePageBridge, webContents, callback);
+        OfflinePageBridgeJni.get().acquireFileAccessPermission(
+                mNativeOfflinePageBridge, OfflinePageBridge.this, webContents, callback);
     }
 
     @CalledByNative
@@ -633,69 +659,65 @@
         return loadUrlParams;
     }
 
-    private static native boolean nativeCanSavePage(String url);
-    private static native OfflinePageBridge nativeGetOfflinePageBridgeForProfileKey(
-            ProfileKey profileKey);
-    @VisibleForTesting
-    native void nativeGetAllPages(long nativeOfflinePageBridge, List<OfflinePageItem> offlinePages,
-            final Callback<List<OfflinePageItem>> callback);
-    private native void nativeWillCloseTab(long nativeOfflinePageBridge, WebContents webContents);
-
-    @VisibleForTesting
-    native void nativeGetPageByOfflineId(
-            long nativeOfflinePageBridge, long offlineId, Callback<OfflinePageItem> callback);
-    @VisibleForTesting
-    native void nativeGetPagesByClientId(long nativeOfflinePageBridge, List<OfflinePageItem> result,
-            String[] namespaces, String[] ids, Callback<List<OfflinePageItem>> callback);
-    native void nativeGetPagesByRequestOrigin(long nativeOfflinePageBridge,
-            List<OfflinePageItem> result, String requestOrigin,
-            Callback<List<OfflinePageItem>> callback);
-    native void nativeGetPagesByNamespace(long nativeOfflinePageBridge,
-            List<OfflinePageItem> result, String nameSpace,
-            Callback<List<OfflinePageItem>> callback);
-    @VisibleForTesting
-    native void nativeDeletePagesByClientId(long nativeOfflinePageBridge, String[] namespaces,
-            String[] ids, Callback<Integer> callback);
-    native void nativeDeletePagesByClientIdAndOrigin(long nativeOfflinePageBridge,
-            String[] namespaces, String[] ids, String origin, Callback<Integer> callback);
-    @VisibleForTesting
-    native void nativeDeletePagesByOfflineId(
-            long nativeOfflinePageBridge, long[] offlineIds, Callback<Integer> callback);
-    @VisibleForTesting
-    private native void nativePublishInternalPageByOfflineId(
-            long nativeOfflinePageBridge, long offlineId, Callback<String> publishedCallback);
-    @VisibleForTesting
-    private native void nativePublishInternalPageByGuid(
-            long nativeOfflinePageBridge, String guid, Callback<String> publishedCallback);
-    private native void nativeSelectPageForOnlineUrl(
-            long nativeOfflinePageBridge, String onlineUrl, int tabId,
-            Callback<OfflinePageItem> callback);
-    private native void nativeSavePage(long nativeOfflinePageBridge, SavePageCallback callback,
-            WebContents webContents, String clientNamespace, String clientId, String origin);
-    private native String nativeGetOfflinePageHeaderForReload(
-            long nativeOfflinePageBridge, WebContents webContents);
-    private native boolean nativeIsShowingOfflinePreview(
-            long nativeOfflinePageBridge, WebContents webContents);
-    private native boolean nativeIsShowingDownloadButtonInErrorPage(
-            long nativeOfflinePageBridge, WebContents webContents);
-    private native void nativeScheduleDownload(long nativeOfflinePageBridge,
-            WebContents webContents, String nameSpace, String url, int uiAction, String origin);
-    private native boolean nativeIsOfflinePage(
-            long nativeOfflinePageBridge, WebContents webContents);
-    private native boolean nativeIsInPrivateDirectory(
-            long nativeOfflinePageBridge, String filePath);
-    private native boolean nativeIsTemporaryNamespace(
-            long nativeOfflinePageBridge, String nameSpace);
-    private native OfflinePageItem nativeGetOfflinePage(
-            long nativeOfflinePageBridge, WebContents webContents);
-    private native void nativeCheckForNewOfflineContent(
-            long nativeOfflinePageBridge, long freshnessTimeMillis, Callback<String> callback);
-    private native void nativeGetLoadUrlParamsByOfflineId(long nativeOfflinePageBridge,
-            long offlineId, int location, Callback<LoadUrlParams> callback);
-    private native boolean nativeIsShowingTrustedOfflinePage(
-            long nativeOfflinePageBridge, WebContents webContents);
-    private native void nativeGetLoadUrlParamsForOpeningMhtmlFileOrContent(
-            long nativeOfflinePageBridge, String url, Callback<LoadUrlParams> callback);
-    private native void nativeAcquireFileAccessPermission(
-            long nativeOfflinePageBridge, WebContents webContents, Callback<Boolean> callback);
+    @NativeMethods
+    interface Natives {
+        boolean canSavePage(String url);
+        OfflinePageBridge getOfflinePageBridgeForProfileKey(ProfileKey profileKey);
+        void getAllPages(long nativeOfflinePageBridge, OfflinePageBridge caller,
+                List<OfflinePageItem> offlinePages, final Callback<List<OfflinePageItem>> callback);
+        void willCloseTab(
+                long nativeOfflinePageBridge, OfflinePageBridge caller, WebContents webContents);
+        void getPageByOfflineId(long nativeOfflinePageBridge, OfflinePageBridge caller,
+                long offlineId, Callback<OfflinePageItem> callback);
+        void getPagesByClientId(long nativeOfflinePageBridge, OfflinePageBridge caller,
+                List<OfflinePageItem> result, String[] namespaces, String[] ids,
+                Callback<List<OfflinePageItem>> callback);
+        void getPagesByRequestOrigin(long nativeOfflinePageBridge, OfflinePageBridge caller,
+                List<OfflinePageItem> result, String requestOrigin,
+                Callback<List<OfflinePageItem>> callback);
+        void getPagesByNamespace(long nativeOfflinePageBridge, OfflinePageBridge caller,
+                List<OfflinePageItem> result, String nameSpace,
+                Callback<List<OfflinePageItem>> callback);
+        void deletePagesByClientId(long nativeOfflinePageBridge, OfflinePageBridge caller,
+                String[] namespaces, String[] ids, Callback<Integer> callback);
+        void deletePagesByClientIdAndOrigin(long nativeOfflinePageBridge, OfflinePageBridge caller,
+                String[] namespaces, String[] ids, String origin, Callback<Integer> callback);
+        void deletePagesByOfflineId(long nativeOfflinePageBridge, OfflinePageBridge caller,
+                long[] offlineIds, Callback<Integer> callback);
+        void publishInternalPageByOfflineId(long nativeOfflinePageBridge, OfflinePageBridge caller,
+                long offlineId, Callback<String> publishedCallback);
+        void publishInternalPageByGuid(long nativeOfflinePageBridge, OfflinePageBridge caller,
+                String guid, Callback<String> publishedCallback);
+        void selectPageForOnlineUrl(long nativeOfflinePageBridge, OfflinePageBridge caller,
+                String onlineUrl, int tabId, Callback<OfflinePageItem> callback);
+        void savePage(long nativeOfflinePageBridge, OfflinePageBridge caller,
+                SavePageCallback callback, WebContents webContents, String clientNamespace,
+                String clientId, String origin);
+        String getOfflinePageHeaderForReload(
+                long nativeOfflinePageBridge, OfflinePageBridge caller, WebContents webContents);
+        boolean isShowingOfflinePreview(
+                long nativeOfflinePageBridge, OfflinePageBridge caller, WebContents webContents);
+        boolean isShowingDownloadButtonInErrorPage(
+                long nativeOfflinePageBridge, OfflinePageBridge caller, WebContents webContents);
+        void scheduleDownload(long nativeOfflinePageBridge, OfflinePageBridge caller,
+                WebContents webContents, String nameSpace, String url, int uiAction, String origin);
+        boolean isOfflinePage(
+                long nativeOfflinePageBridge, OfflinePageBridge caller, WebContents webContents);
+        boolean isInPrivateDirectory(
+                long nativeOfflinePageBridge, OfflinePageBridge caller, String filePath);
+        boolean isTemporaryNamespace(
+                long nativeOfflinePageBridge, OfflinePageBridge caller, String nameSpace);
+        OfflinePageItem getOfflinePage(
+                long nativeOfflinePageBridge, OfflinePageBridge caller, WebContents webContents);
+        void checkForNewOfflineContent(long nativeOfflinePageBridge, OfflinePageBridge caller,
+                long freshnessTimeMillis, Callback<String> callback);
+        void getLoadUrlParamsByOfflineId(long nativeOfflinePageBridge, OfflinePageBridge caller,
+                long offlineId, int location, Callback<LoadUrlParams> callback);
+        boolean isShowingTrustedOfflinePage(
+                long nativeOfflinePageBridge, OfflinePageBridge caller, WebContents webContents);
+        void getLoadUrlParamsForOpeningMhtmlFileOrContent(long nativeOfflinePageBridge,
+                OfflinePageBridge caller, String url, Callback<LoadUrlParams> callback);
+        void acquireFileAccessPermission(long nativeOfflinePageBridge, OfflinePageBridge caller,
+                WebContents webContents, Callback<Boolean> callback);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTask.java b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTask.java
index df368f1..44155a0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTask.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTask.java
@@ -9,6 +9,7 @@
 import org.chromium.base.VisibleForTesting;
 import org.chromium.base.annotations.CalledByNative;
 import org.chromium.base.annotations.JNINamespace;
+import org.chromium.base.annotations.NativeMethods;
 import org.chromium.chrome.browser.ChromeFeatureList;
 import org.chromium.chrome.browser.DeviceConditions;
 import org.chromium.chrome.browser.background_task_scheduler.NativeBackgroundTask;
@@ -108,7 +109,7 @@
             return;
         }
 
-        nativeStartPrefetchTask();
+        PrefetchBackgroundTaskJni.get().startPrefetchTask(PrefetchBackgroundTask.this);
     }
 
     private boolean isBrowserRunningInReducedMode() {
@@ -127,7 +128,7 @@
         // TaskFinishedCallback, so we need to save the reschedule result.
         if (mNativeTask == 0) return mCachedRescheduleResult;
 
-        return nativeOnStopTask(mNativeTask);
+        return PrefetchBackgroundTaskJni.get().onStopTask(mNativeTask, PrefetchBackgroundTask.this);
     }
 
     @Override
@@ -187,13 +188,15 @@
     @VisibleForTesting
     void setTaskReschedulingForTesting(int rescheduleType) {
         if (mNativeTask == 0) return;
-        nativeSetTaskReschedulingForTesting(mNativeTask, rescheduleType);
+        PrefetchBackgroundTaskJni.get().setTaskReschedulingForTesting(
+                mNativeTask, PrefetchBackgroundTask.this, rescheduleType);
     }
 
     @VisibleForTesting
     void signalTaskFinishedForTesting() {
         if (mNativeTask == 0) return;
-        nativeSignalTaskFinishedForTesting(mNativeTask);
+        PrefetchBackgroundTaskJni.get().signalTaskFinishedForTesting(
+                mNativeTask, PrefetchBackgroundTask.this);
     }
 
     @Override
@@ -205,11 +208,13 @@
         return FeatureUtilities.isServiceManagerForBackgroundPrefetchEnabled();
     }
 
-    @VisibleForTesting
-    native boolean nativeStartPrefetchTask();
-    @VisibleForTesting
-    native boolean nativeOnStopTask(long nativePrefetchBackgroundTaskAndroid);
-    native void nativeSetTaskReschedulingForTesting(
-            long nativePrefetchBackgroundTaskAndroid, int rescheduleType);
-    native void nativeSignalTaskFinishedForTesting(long nativePrefetchBackgroundTaskAndroid);
+    @NativeMethods
+    interface Natives {
+        boolean startPrefetchTask(PrefetchBackgroundTask caller);
+        boolean onStopTask(long nativePrefetchBackgroundTaskAndroid, PrefetchBackgroundTask caller);
+        void setTaskReschedulingForTesting(long nativePrefetchBackgroundTaskAndroid,
+                PrefetchBackgroundTask caller, int rescheduleType);
+        void signalTaskFinishedForTesting(
+                long nativePrefetchBackgroundTaskAndroid, PrefetchBackgroundTask caller);
+    }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizer.java b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizer.java
index 1c7dd31..1b8d262 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizer.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizer.java
@@ -181,7 +181,7 @@
                 switch (securityLevel) {
                     case ConnectionSecurityLevel.NONE:
                     // Intentional fall-through:
-                    case ConnectionSecurityLevel.HTTP_SHOW_WARNING:
+                    case ConnectionSecurityLevel.WARNING:
                         // Draw attention to the data: URI scheme for anti-spoofing reasons.
                         if (UrlConstants.DATA_SCHEME.equals(
                                     emphasizeResponse.extractScheme(urlString))) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
index 3480b12..93778f6b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/LocationBarModel.java
@@ -382,7 +382,7 @@
             assert securityLevel != ConnectionSecurityLevel.DANGEROUS;
             return (URI.create(publisherUrl).getScheme().equals(UrlConstants.HTTPS_SCHEME))
                     ? ConnectionSecurityLevel.SECURE
-                    : ConnectionSecurityLevel.HTTP_SHOW_WARNING;
+                    : ConnectionSecurityLevel.WARNING;
         }
         return securityLevel;
     }
@@ -406,7 +406,7 @@
                                         || getNewTabPageForCurrentTab() != null)
                         ? 0
                         : R.drawable.omnibox_info;
-            case ConnectionSecurityLevel.HTTP_SHOW_WARNING:
+            case ConnectionSecurityLevel.WARNING:
                 return R.drawable.omnibox_info;
             case ConnectionSecurityLevel.DANGEROUS:
                 return R.drawable.omnibox_https_invalid;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java
index 00394a6f..6a01845e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/toolbar/ToolbarDataProvider.java
@@ -128,7 +128,7 @@
     default int getSecurityIconContentDescription() {
         switch (getSecurityLevel()) {
             case ConnectionSecurityLevel.NONE:
-            case ConnectionSecurityLevel.HTTP_SHOW_WARNING:
+            case ConnectionSecurityLevel.WARNING:
                 return R.string.accessibility_security_btn_warn;
             case ConnectionSecurityLevel.DANGEROUS:
                 return R.string.accessibility_security_btn_dangerous;
@@ -157,7 +157,7 @@
      */
     @Nullable
     @Override
-    default public String getDisplaySearchTerms() {
+    public default String getDisplaySearchTerms() {
         return null;
     }
 }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/ViewUtils.java b/chrome/android/java/src/org/chromium/chrome/browser/util/ViewUtils.java
index 9b50566..62e97e0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/util/ViewUtils.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/util/ViewUtils.java
@@ -16,8 +16,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 
-import androidx.annotation.DrawableRes;
-
 import org.chromium.base.ApiCompatibilityUtils;
 import org.chromium.base.ContextUtils;
 import org.chromium.chrome.R;
@@ -126,20 +124,6 @@
     }
 
     /**
-     * Sets the background of a view to the given 9-patch resource and restores its padding. This
-     * works around a bug in Android where the padding is lost when a 9-patch resource is applied
-     * programmatically.
-     */
-    public static void setNinePatchBackgroundResource(View view, @DrawableRes int resource) {
-        int left = view.getPaddingLeft();
-        int top = view.getPaddingTop();
-        int right = view.getPaddingRight();
-        int bottom = view.getPaddingBottom();
-        view.setBackgroundResource(resource);
-        view.setPadding(left, top, right, bottom);
-    }
-
-    /**
      *  Converts density-independent pixels (dp) to pixels on the screen (px).
      *
      *  @param dp Density-independent pixels are based on the physical density of the screen.
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizerTest.java
index f959a54..98ba9e8 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizerTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizerTest.java
@@ -234,8 +234,8 @@
     @Feature({"Browser", "Main"})
     public void testVeryShortHTTPWarningUrl() throws Throwable {
         Spannable url = new SpannableStringBuilder("m.w.co/p");
-        OmniboxUrlEmphasizer.emphasizeUrl(url, mResources, mProfile,
-                ConnectionSecurityLevel.HTTP_SHOW_WARNING, false, true, false);
+        OmniboxUrlEmphasizer.emphasizeUrl(
+                url, mResources, mProfile, ConnectionSecurityLevel.WARNING, false, true, false);
         EmphasizedUrlSpanHelper[] spans = getSpansForEmphasizedUrl(url);
 
         Assert.assertEquals("Unexpected number of spans:", 2, spans.length);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappVisibilityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappVisibilityTest.java
index 2ce0db1..2dc421c 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappVisibilityTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/webapps/WebappVisibilityTest.java
@@ -65,7 +65,7 @@
         Assert.assertTrue(canAutoHideBrowserControls(ConnectionSecurityLevel.NONE));
         Assert.assertTrue(canAutoHideBrowserControls(ConnectionSecurityLevel.SECURE));
         Assert.assertTrue(canAutoHideBrowserControls(ConnectionSecurityLevel.EV_SECURE));
-        Assert.assertTrue(canAutoHideBrowserControls(ConnectionSecurityLevel.HTTP_SHOW_WARNING));
+        Assert.assertTrue(canAutoHideBrowserControls(ConnectionSecurityLevel.WARNING));
         Assert.assertFalse(canAutoHideBrowserControls(ConnectionSecurityLevel.DANGEROUS));
     }
 
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java
index 5c7060a2..30e0d3d 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/OfflinePageBridgeUnitTest.java
@@ -8,16 +8,19 @@
 import static org.junit.Assert.assertNotNull;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
 import org.mockito.Captor;
+import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
@@ -27,6 +30,7 @@
 import org.chromium.base.Callback;
 import org.chromium.base.test.BaseRobolectricTestRunner;
 import org.chromium.base.test.util.Feature;
+import org.chromium.base.test.util.JniMocker;
 import org.chromium.chrome.browser.offlinepages.OfflinePageBridge.OfflinePageModelObserver;
 
 import java.util.ArrayList;
@@ -74,6 +78,12 @@
     @Captor
     ArgumentCaptor<Callback<Integer>> mDeleteCallbackArgument;
 
+    @Rule
+    public JniMocker mocker = new JniMocker();
+
+    @Mock
+    OfflinePageBridge.Natives mOfflinePageBridgeJniMock;
+
     /**
      * Mocks the observer.
      */
@@ -91,6 +101,7 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+        mocker.mock(OfflinePageBridgeJni.TEST_HOOKS, mOfflinePageBridgeJniMock);
         OfflinePageBridge bridge = new OfflinePageBridge(0);
         // Using the spy to automatically marshal all the calls to the original methods if they are
         // not mocked explicitly.
@@ -310,8 +321,10 @@
                 return null;
             }
         };
-        doAnswer(answer).when(mBridge).nativeGetAllPages(
-                anyLong(), mResultArgument.capture(), mCallbackArgument.capture());
+        doAnswer(answer)
+                .when(mOfflinePageBridgeJniMock)
+                .getAllPages(anyLong(), eq(mBridge), mResultArgument.capture(),
+                        mCallbackArgument.capture());
     }
 
     private void answerGetPagesByClientIds(final int itemCount) {
@@ -335,9 +348,11 @@
             }
         };
 
-        doAnswer(answer).when(mBridge).nativeGetPagesByClientId(anyLong(),
-                mResultArgument.capture(), mNamespacesArgument.capture(), mIdsArgument.capture(),
-                mCallbackArgument.capture());
+        doAnswer(answer)
+                .when(mOfflinePageBridgeJniMock)
+                .getPagesByClientId(anyLong(), eq(mBridge), mResultArgument.capture(),
+                        mNamespacesArgument.capture(), mIdsArgument.capture(),
+                        mCallbackArgument.capture());
     }
 
     private void answerDeletePagesByOfflineIds(final int itemCount) {
@@ -357,8 +372,10 @@
             }
         };
 
-        doAnswer(answer).when(mBridge).nativeDeletePagesByOfflineId(
-                anyLong(), mOfflineIdsArgument.capture(), mDeleteCallbackArgument.capture());
+        doAnswer(answer)
+                .when(mOfflinePageBridgeJniMock)
+                .deletePagesByOfflineId(anyLong(), eq(mBridge), mOfflineIdsArgument.capture(),
+                        mDeleteCallbackArgument.capture());
     }
 
     private void answerDeletePagesByClientIds(final int itemCount) {
@@ -377,8 +394,9 @@
             }
         };
 
-        doAnswer(answer).when(mBridge).nativeDeletePagesByClientId(anyLong(),
-                mNamespacesArgument.capture(), mIdsArgument.capture(),
-                mDeleteCallbackArgument.capture());
+        doAnswer(answer)
+                .when(mOfflinePageBridgeJniMock)
+                .deletePagesByClientId(anyLong(), eq(mBridge), mNamespacesArgument.capture(),
+                        mIdsArgument.capture(), mDeleteCallbackArgument.capture());
     }
 }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskUnitTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskUnitTest.java
index d61ec381..55b46d6 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskUnitTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/offlinepages/prefetch/PrefetchBackgroundTaskUnitTest.java
@@ -18,6 +18,7 @@
 import android.os.Bundle;
 
 import org.junit.Before;
+import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentCaptor;
@@ -33,6 +34,7 @@
 
 import org.chromium.base.library_loader.ProcessInitException;
 import org.chromium.base.test.BaseRobolectricTestRunner;
+import org.chromium.base.test.util.JniMocker;
 import org.chromium.chrome.browser.DeviceConditions;
 import org.chromium.chrome.browser.ShadowDeviceConditions;
 import org.chromium.chrome.browser.background_task_scheduler.NativeBackgroundTask;
@@ -92,10 +94,14 @@
     public static final boolean METERED = true;
     public static final boolean SCREEN_ON_AND_UNLOCKED = true;
 
+    @Rule
+    public JniMocker mocker = new JniMocker();
     @Spy
     private PrefetchBackgroundTask mPrefetchBackgroundTask = new PrefetchBackgroundTask();
     @Mock
     private ChromeBrowserInitializer mChromeBrowserInitializer;
+    @Mock
+    private PrefetchBackgroundTask.Natives mPrefetchBackgroundTaskJniMock;
     @Captor
     ArgumentCaptor<BrowserParts> mBrowserParts;
     private FakeBackgroundTaskScheduler mFakeTaskScheduler;
@@ -103,6 +109,7 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        mocker.mock(PrefetchBackgroundTaskJni.TEST_HOOKS, mPrefetchBackgroundTaskJniMock);
         doNothing().when(mChromeBrowserInitializer).handlePreNativeStartup(any(BrowserParts.class));
         try {
             doAnswer(new Answer<Void>() {
@@ -127,9 +134,10 @@
                 return Boolean.TRUE;
             }
         })
-                .when(mPrefetchBackgroundTask)
-                .nativeStartPrefetchTask();
-        doReturn(true).when(mPrefetchBackgroundTask).nativeOnStopTask(1);
+                .when(mPrefetchBackgroundTaskJniMock)
+                .startPrefetchTask(mPrefetchBackgroundTask);
+
+        doReturn(true).when(mPrefetchBackgroundTaskJniMock).onStopTask(1, mPrefetchBackgroundTask);
 
         mFakeTaskScheduler = new FakeBackgroundTaskScheduler();
         BackgroundTaskSchedulerFactory.setSchedulerForTesting(mFakeTaskScheduler);
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java
index 0a44ca6cc..4bb5340 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/toolbar/ToolbarSecurityIconTest.java
@@ -33,7 +33,7 @@
     private static final boolean IS_OFFLINE_PAGE = true;
     private static final boolean IS_PREVIEW = true;
     private static final int[] SECURITY_LEVELS = new int[] {ConnectionSecurityLevel.NONE,
-            ConnectionSecurityLevel.HTTP_SHOW_WARNING, ConnectionSecurityLevel.DANGEROUS,
+            ConnectionSecurityLevel.WARNING, ConnectionSecurityLevel.DANGEROUS,
             ConnectionSecurityLevel.SECURE, ConnectionSecurityLevel.EV_SECURE};
 
     @Mock
@@ -72,7 +72,7 @@
                 ConnectionSecurityLevel.SECURE,
                 LocationBarModel.getSecurityLevel(mTab, !IS_OFFLINE_PAGE, "https://example.com"));
         assertEquals("Wrong security level returned for HTTP publisher URL",
-                ConnectionSecurityLevel.HTTP_SHOW_WARNING,
+                ConnectionSecurityLevel.WARNING,
                 LocationBarModel.getSecurityLevel(mTab, !IS_OFFLINE_PAGE, "http://example.com"));
 
         when(mTab.getSecurityLevel()).thenReturn(ConnectionSecurityLevel.DANGEROUS);
@@ -110,10 +110,10 @@
                         !IS_SMALL_DEVICE, !IS_OFFLINE_PAGE, !IS_PREVIEW));
 
         assertEquals(R.drawable.omnibox_info,
-                mLocationBarModel.getSecurityIconResource(ConnectionSecurityLevel.HTTP_SHOW_WARNING,
+                mLocationBarModel.getSecurityIconResource(ConnectionSecurityLevel.WARNING,
                         IS_SMALL_DEVICE, !IS_OFFLINE_PAGE, !IS_PREVIEW));
         assertEquals(R.drawable.omnibox_info,
-                mLocationBarModel.getSecurityIconResource(ConnectionSecurityLevel.HTTP_SHOW_WARNING,
+                mLocationBarModel.getSecurityIconResource(ConnectionSecurityLevel.WARNING,
                         !IS_SMALL_DEVICE, !IS_OFFLINE_PAGE, !IS_PREVIEW));
 
         assertEquals(R.drawable.omnibox_https_invalid,
diff --git a/chrome/app_shim/chrome_main_app_mode_mac.mm b/chrome/app_shim/chrome_main_app_mode_mac.mm
index 6627c62e..ae074fb 100644
--- a/chrome/app_shim/chrome_main_app_mode_mac.mm
+++ b/chrome/app_shim/chrome_main_app_mode_mac.mm
@@ -155,7 +155,13 @@
     // <user_data_dir>/<profile_dir>/Web Applications/_crx_extensionid/.
     controller_params.user_data_dir =
         base::FilePath(info->user_data_dir).DirName().DirName().DirName();
-    controller_params.profile_dir = base::FilePath(info->profile_dir);
+    // Similarly, extract the full profile path from |info->user_data_dir|.
+    // Ignore |info->profile_dir| because it is only the relative path (unless
+    // it is empty, in which case this is a profile-agnostic app).
+    if (!base::FilePath(info->profile_dir).empty()) {
+      controller_params.profile_dir =
+          base::FilePath(info->user_data_dir).DirName().DirName();
+    }
     controller_params.app_id = info->app_mode_id;
     controller_params.app_name = base::UTF8ToUTF16(info->app_mode_name);
     controller_params.app_url = GURL(info->app_mode_url);
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 8950a0ce8..a7a593a 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -763,6 +763,10 @@
     "media/webrtc/window_icon_util_chromeos.cc",
     "media/webrtc/window_icon_util_mac.mm",
     "media/webrtc/window_icon_util_win.cc",
+    "memory/enterprise_memory_limit_evaluator.cc",
+    "memory/enterprise_memory_limit_evaluator.h",
+    "memory/enterprise_memory_limit_pref_observer.cc",
+    "memory/enterprise_memory_limit_pref_observer.h",
     "memory_details.cc",
     "memory_details.h",
     "memory_details_android.cc",
@@ -1931,6 +1935,7 @@
     ":resource_prefetch_predictor_proto",
     "//base:i18n",
     "//base/allocator:buildflags",
+    "//base/util/memory_pressure:memory_pressure",
     "//base/util/values:values_util",
     "//build:branding_buildflags",
     "//cc",
@@ -3200,8 +3205,6 @@
       "media_galleries/win/portable_device_map_service.h",
       "media_galleries/win/snapshot_file_details.cc",
       "media_galleries/win/snapshot_file_details.h",
-      "memory/enterprise_memory_limit_evaluator.cc",
-      "memory/enterprise_memory_limit_evaluator.h",
       "memory/memory_pressure_monitor.cc",
       "memory/memory_pressure_monitor.h",
       "memory/memory_pressure_monitor_utils.cc",
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index d840695..c6483761 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -2807,10 +2807,6 @@
      flag_descriptions::kOmniboxTabSwitchSuggestionsDedicatedRowDescription,
      kOsDesktop,
      FEATURE_VALUE_TYPE(omnibox::kOmniboxTabSwitchSuggestionsDedicatedRow)},
-    {"omnibox-wrap-popup-position",
-     flag_descriptions::kOmniboxWrapPopupPositionName,
-     flag_descriptions::kOmniboxWrapPopupPositionDescription, kOsDesktop,
-     FEATURE_VALUE_TYPE(omnibox::kOmniboxWrapPopupPosition)},
     {"omnibox-pedal-suggestions",
      flag_descriptions::kOmniboxPedalSuggestionsName,
      flag_descriptions::kOmniboxPedalSuggestionsDescription, kOsDesktop,
diff --git a/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc b/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc
index e67ce3b..0f25772 100644
--- a/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc
+++ b/chrome/browser/android/contextualsearch/contextual_search_delegate_unittest.cc
@@ -383,7 +383,7 @@
   auto* pending_request = test_url_loader_factory_.GetPendingRequest(0);
   test_url_loader_factory_.SimulateResponseForPendingRequest(
       pending_request->request.url, network::URLLoaderCompletionStatus(net::OK),
-      network::ResourceResponseHead(), std::string());
+      network::mojom::URLResponseHead::New(), std::string());
   base::RunLoop().RunUntilIdle();
 
   EXPECT_FALSE(do_prevent_preload());
diff --git a/chrome/browser/android/digital_asset_links/digital_asset_links_handler_unittest.cc b/chrome/browser/android/digital_asset_links/digital_asset_links_handler_unittest.cc
index 3815bc7..050cf1a 100644
--- a/chrome/browser/android/digital_asset_links/digital_asset_links_handler_unittest.cc
+++ b/chrome/browser/android/digital_asset_links/digital_asset_links_handler_unittest.cc
@@ -82,15 +82,15 @@
     request_url_ =
         test_url_loader_factory_.pending_requests()->at(0).request.url;
 
-    network::ResourceResponseHead response_head;
+    auto response_head = network::mojom::URLResponseHead::New();
     std::string status_line =
         "HTTP/1.1 " + base::NumberToString(response_code) + " " +
         net::GetHttpReasonPhrase(
             static_cast<net::HttpStatusCode>(response_code));
-    response_head.headers =
+    response_head->headers =
         base::MakeRefCounted<net::HttpResponseHeaders>(status_line);
     test_url_loader_factory_.AddResponse(
-        request_url_, response_head, "",
+        request_url_, std::move(response_head), "",
         network::URLLoaderCompletionStatus(error));
 
     base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/android/explore_sites/explore_sites_fetcher_unittest.cc b/chrome/browser/android/explore_sites/explore_sites_fetcher_unittest.cc
index b6d15eb8..81811a94 100644
--- a/chrome/browser/android/explore_sites/explore_sites_fetcher_unittest.cc
+++ b/chrome/browser/android/explore_sites/explore_sites_fetcher_unittest.cc
@@ -184,18 +184,18 @@
   network::URLLoaderCompletionStatus completion_status(net_error);
   test_url_loader_factory_.SimulateResponseForPendingRequest(
       GetLastPendingRequest()->request.url, completion_status,
-      network::ResourceResponseHead(), std::string(),
+      network::mojom::URLResponseHead::New(), std::string(),
       network::TestURLLoaderFactory::kMostRecentMatch);
 }
 
 void ExploreSitesFetcherTest::RespondWithHttpError(
     net::HttpStatusCode http_error) {
   int pending_requests_count = test_url_loader_factory_.NumPending();
-  auto resource_response_head = network::CreateResourceResponseHead(http_error);
+  auto url_response_head = network::CreateURLResponseHead(http_error);
   DCHECK(pending_requests_count > 0);
   test_url_loader_factory_.SimulateResponseForPendingRequest(
       GetLastPendingRequest()->request.url,
-      network::URLLoaderCompletionStatus(net::OK), resource_response_head,
+      network::URLLoaderCompletionStatus(net::OK), std::move(url_response_head),
       std::string(), network::TestURLLoaderFactory::kMostRecentMatch);
 }
 
diff --git a/chrome/browser/apps/app_shim/app_shim_host_mac.cc b/chrome/browser/apps/app_shim/app_shim_host_mac.cc
index 2759cab..25d486a 100644
--- a/chrome/browser/apps/app_shim/app_shim_host_mac.cc
+++ b/chrome/browser/apps/app_shim/app_shim_host_mac.cc
@@ -157,6 +157,8 @@
 }
 
 base::FilePath AppShimHost::GetProfilePath() const {
+  // This should only be used by single-profile-app paths.
+  DCHECK(!profile_path_.empty());
   return profile_path_;
 }
 
diff --git a/chrome/browser/apps/app_shim/app_shim_host_mac.h b/chrome/browser/apps/app_shim/app_shim_host_mac.h
index bb188d7..cfcce208 100644
--- a/chrome/browser/apps/app_shim/app_shim_host_mac.h
+++ b/chrome/browser/apps/app_shim/app_shim_host_mac.h
@@ -92,7 +92,7 @@
   // Return the app shim interface.
   chrome::mojom::AppShim* GetAppShim() const;
 
- private:
+ protected:
   void ChannelError(uint32_t custom_reason, const std::string& description);
 
   // Helper function to launch the app shim process.
diff --git a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc
index 741dbb54f..7780ff51 100644
--- a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc
+++ b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.cc
@@ -267,22 +267,6 @@
       &profile_manager->GetProfileAttributesStorage(), observer, nullptr);
 }
 
-base::FilePath ExtensionAppShimHandler::Delegate::GetFullProfilePath(
-    const base::FilePath& relative_profile_path) {
-  ProfileManager* profile_manager = g_browser_process->profile_manager();
-  return profile_manager->user_data_dir().Append(relative_profile_path);
-}
-
-bool ExtensionAppShimHandler::Delegate::ProfileExistsForPath(
-    const base::FilePath& full_path) {
-  ProfileManager* profile_manager = g_browser_process->profile_manager();
-  // Check for the profile name in the profile info cache to ensure that we
-  // never access any directory that isn't a known profile.
-  ProfileAttributesEntry* entry;
-  return profile_manager->GetProfileAttributesStorage().
-      GetProfileAttributesWithPath(full_path, &entry);
-}
-
 Profile* ExtensionAppShimHandler::Delegate::ProfileForPath(
     const base::FilePath& full_path) {
   ProfileManager* profile_manager = g_browser_process->profile_manager();
@@ -333,10 +317,11 @@
 
 std::unique_ptr<AppShimHost> ExtensionAppShimHandler::Delegate::CreateHost(
     AppShimHost::Client* client,
-    Profile* profile,
-    const extensions::Extension* extension) {
-  return std::make_unique<AppShimHost>(
-      client, extension->id(), profile->GetPath(), UsesRemoteViews(extension));
+    const base::FilePath& profile_path,
+    const std::string& app_id,
+    bool use_remote_cocoa) {
+  return std::make_unique<AppShimHost>(client, app_id, profile_path,
+                                       use_remote_cocoa);
 }
 
 void ExtensionAppShimHandler::Delegate::EnableExtension(
@@ -489,7 +474,22 @@
     bool recreate_shims,
     apps::ShimLaunchedCallback launched_callback,
     apps::ShimTerminatedCallback terminated_callback) {
-  Profile* profile = delegate_->ProfileForPath(host->GetProfilePath());
+  // A shim can only be launched through an active profile, so find a profile
+  // through which to do the launch. For multi-profile apps, select one
+  // arbitrarily. For non-multi-profile apps, select the specified profile.
+  Profile* profile = nullptr;
+  {
+    auto found_app = apps_.find(host->GetAppId());
+    DCHECK(found_app != apps_.end());
+    AppState* app_state = found_app->second.get();
+    if (app_state->IsMultiProfile()) {
+      DCHECK(!app_state->profiles.empty());
+      profile = app_state->profiles.begin()->first;
+    } else {
+      profile = delegate_->ProfileForPath(host->GetProfilePath());
+    }
+  }
+
   const Extension* extension =
       delegate_->MaybeGetAppExtension(profile, host->GetAppId());
   if (!profile || !extension) {
@@ -508,19 +508,9 @@
   const std::string& app_id = bootstrap->GetAppId();
   DCHECK(crx_file::id_util::IdIsValid(app_id));
 
-  const base::FilePath& relative_profile_path = bootstrap->GetProfilePath();
-  DCHECK(!relative_profile_path.empty());
-  base::FilePath profile_path =
-      delegate_->GetFullProfilePath(relative_profile_path);
-
-  if (!delegate_->ProfileExistsForPath(profile_path)) {
-    // User may have deleted the profile this shim was originally created for.
-    // TODO(jackhou): Add some UI for this case and remove the LOG.
-    LOG(ERROR) << "Requested directory is not a known profile '"
-               << profile_path.value() << "'.";
-    bootstrap->OnFailedToConnectToHost(APP_SHIM_LAUNCH_PROFILE_NOT_FOUND);
-    return;
-  }
+  // TODO(https://crbug.com/982024): If no profile path is specified by the
+  // bootstrap, then load an appropriate profile.
+  base::FilePath profile_path = bootstrap->GetProfilePath();
 
   if (delegate_->IsProfileLockedForPath(profile_path)) {
     LOG(WARNING) << "Requested profile is locked.  Showing User Manager.";
@@ -529,19 +519,11 @@
     return;
   }
 
-  Profile* profile = delegate_->ProfileForPath(profile_path);
-  if (profile) {
-    OnProfileLoaded(std::move(bootstrap), profile);
-  } else {
-    // If the profile is not loaded, this must have been a launch by the shim.
-    // Load the profile asynchronously, the host will be registered in
-    // OnProfileLoaded.
-    DCHECK_EQ(APP_SHIM_LAUNCH_NORMAL, bootstrap->GetLaunchType());
-    delegate_->LoadProfileAsync(
-        profile_path,
-        base::BindOnce(&ExtensionAppShimHandler::OnProfileLoaded,
-                       weak_factory_.GetWeakPtr(), std::move(bootstrap)));
-  }
+  LoadProfileAndApp(
+      profile_path, app_id,
+      base::BindOnce(
+          &ExtensionAppShimHandler::OnShimProcessConnectedAndAppLoaded,
+          weak_factory_.GetWeakPtr(), std::move(bootstrap)));
 }
 
 // static
@@ -577,11 +559,35 @@
     apps_.erase(found_app);
 }
 
+void ExtensionAppShimHandler::LoadProfileAndApp(
+    const base::FilePath& profile_path,
+    const std::string& app_id,
+    LoadProfileAppCallback callback) {
+  Profile* profile = delegate_->ProfileForPath(profile_path);
+  if (profile) {
+    OnProfileLoaded(profile_path, app_id, std::move(callback), profile);
+  } else {
+    delegate_->LoadProfileAsync(
+        profile_path, base::BindOnce(&ExtensionAppShimHandler::OnProfileLoaded,
+                                     weak_factory_.GetWeakPtr(), profile_path,
+                                     app_id, std::move(callback)));
+  }
+}
+
 void ExtensionAppShimHandler::OnProfileLoaded(
-    std::unique_ptr<AppShimHostBootstrap> bootstrap,
+    const base::FilePath& profile_path,
+    const std::string& app_id,
+    LoadProfileAppCallback callback,
     Profile* profile) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  const std::string& app_id = bootstrap->GetAppId();
+  if (!profile) {
+    // User may have deleted the profile this shim was originally created for.
+    // TODO(jackhou): Add some UI for this case and remove the LOG.
+    LOG(ERROR) << "Requested directory is not a known profile '"
+               << profile_path.value() << "'.";
+    std::move(callback).Run(profile, nullptr);
+    return;
+  }
 
   // TODO(jeremya): Handle the case that launching the app fails. Probably we
   // need to watch for 'app successfully launched' or at least 'background page
@@ -589,44 +595,51 @@
   // life within a certain window.
   const Extension* extension = delegate_->MaybeGetAppExtension(profile, app_id);
   if (extension) {
-    OnExtensionEnabled(std::move(bootstrap));
+    std::move(callback).Run(profile, extension);
   } else {
     delegate_->EnableExtension(
         profile, app_id,
-        base::BindOnce(&ExtensionAppShimHandler::OnExtensionEnabled,
-                       weak_factory_.GetWeakPtr(), std::move(bootstrap)));
+        base::BindOnce(&ExtensionAppShimHandler::OnAppEnabled,
+                       weak_factory_.GetWeakPtr(), profile_path, app_id,
+                       std::move(callback)));
   }
 }
 
-void ExtensionAppShimHandler::OnExtensionEnabled(
-    std::unique_ptr<AppShimHostBootstrap> bootstrap) {
-  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
-  AppShimLaunchType launch_type = bootstrap->GetLaunchType();
-  std::vector<base::FilePath> files = bootstrap->GetLaunchFiles();
-
+void ExtensionAppShimHandler::OnAppEnabled(const base::FilePath& profile_path,
+                                           const std::string& app_id,
+                                           LoadProfileAppCallback callback) {
   // If the profile doesn't exist, it may have been deleted during the enable
   // prompt.
-  base::FilePath profile_path =
-      delegate_->GetFullProfilePath(bootstrap->GetProfilePath());
   Profile* profile = delegate_->ProfileForPath(profile_path);
+  const Extension* extension =
+      profile ? delegate_->MaybeGetAppExtension(profile, app_id) : nullptr;
+  std::move(callback).Run(profile, extension);
+}
+
+void ExtensionAppShimHandler::OnShimProcessConnectedAndAppLoaded(
+    std::unique_ptr<AppShimHostBootstrap> bootstrap,
+    Profile* profile,
+    const extensions::Extension* extension) {
+  DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+  // Early-out if the profile or extension failed to load.
   if (!profile) {
     bootstrap->OnFailedToConnectToHost(APP_SHIM_LAUNCH_PROFILE_NOT_FOUND);
     return;
   }
-
-  // If !extension, the extension doesn't exist, or was not re-enabled.
-  const Extension* extension =
-      delegate_->MaybeGetAppExtension(profile, bootstrap->GetAppId());
   if (!extension) {
     bootstrap->OnFailedToConnectToHost(APP_SHIM_LAUNCH_APP_NOT_FOUND);
     return;
   }
+  AppShimLaunchType launch_type = bootstrap->GetLaunchType();
+  std::vector<base::FilePath> files = bootstrap->GetLaunchFiles();
 
   ProfileState* profile_state =
       delegate_->AllowShimToConnect(profile, extension)
           ? GetOrCreateProfileState(profile, extension)
           : nullptr;
   if (profile_state) {
+    DCHECK_EQ(profile_state->app_state->IsMultiProfile(),
+              bootstrap->IsMultiProfile());
     AppShimHost* host = profile_state->GetHost();
     if (host->HasBootstrapConnected()) {
       // If another app shim process has already connected to this (profile,
@@ -667,34 +680,42 @@
 }
 
 void ExtensionAppShimHandler::OnShimProcessDisconnected(AppShimHost* host) {
-  Profile* profile = delegate_->ProfileForPath(host->GetProfilePath());
   const std::string app_id = host->GetAppId();
 
+  auto found_app = apps_.find(app_id);
+  DCHECK(found_app != apps_.end());
+  AppState* app_state = found_app->second.get();
+  DCHECK(app_state);
+
+  // For multi-profile apps, just delete the AppState, which will take down
+  // |host| and all profiles' state.
+  if (app_state->IsMultiProfile()) {
+    DCHECK_EQ(host, app_state->multi_profile_host.get());
+    apps_.erase(found_app);
+    return;
+  }
+
+  Profile* profile = delegate_->ProfileForPath(host->GetProfilePath());
+
   // For non-RemoteCocoa apps, close all of the windows only if the the shim
   // process has successfully connected (if it never connected, then let the
   // app run as normal).
   bool close_windows =
       !host->UsesRemoteViews() && host->HasBootstrapConnected();
 
-  // Find the AppState or ProfileState that owns |host| and delete it. Note
-  // that that will destroy |host| as well.
-  auto found_app = apps_.find(app_id);
-  DCHECK(found_app != apps_.end());
-  AppState* app_state = found_app->second.get();
-  if (app_state->IsMultiProfile()) {
-    DCHECK_EQ(host, app_state->multi_profile_host.get());
-    apps_.erase(found_app);
-  } else {
-    auto found_profile = app_state->profiles.find(profile);
-    DCHECK(found_profile != app_state->profiles.end());
-    ProfileState* profile_state = found_profile->second.get();
-    DCHECK_EQ(host, profile_state->single_profile_host.get());
-    app_state->profiles.erase(found_profile);
-    if (app_state->profiles.empty())
-      apps_.erase(found_app);
-  }
+  // Erase the ProfileState, which will delete |host|.
+  auto found_profile = app_state->profiles.find(profile);
+  DCHECK(found_profile != app_state->profiles.end());
+  ProfileState* profile_state = found_profile->second.get();
+  DCHECK_EQ(host, profile_state->single_profile_host.get());
+  app_state->profiles.erase(found_profile);
   host = nullptr;
 
+  // Erase |app_state| if this was the last profile.
+  if (app_state->profiles.empty())
+    apps_.erase(found_app);
+
+  // Close app windows if we decided to do so above.
   if (close_windows) {
     AppWindowList windows = delegate_->GetWindows(profile, app_id);
     for (auto it = windows.begin(); it != windows.end(); ++it) {
@@ -708,6 +729,7 @@
     AppShimHost* host,
     AppShimFocusType focus_type,
     const std::vector<base::FilePath>& files) {
+  // This path is only for legacy apps (which are perforce single-profile).
   if (host->UsesRemoteViews())
     return;
 
@@ -735,13 +757,36 @@
 void ExtensionAppShimHandler::OnShimSelectedProfile(
     AppShimHost* host,
     const base::FilePath& profile_path) {
-  // TODO(https://crbug.com/982024): Handle the case where the profile exists
-  // but is not loaded yet.
-  Profile* profile = delegate_->ProfileForPath(profile_path);
-  const Extension* extension =
-      delegate_->MaybeGetAppExtension(profile, host->GetAppId());
-  std::vector<base::FilePath> files;
-  delegate_->LaunchApp(profile, extension, files);
+  LoadProfileAndApp(
+      profile_path, host->GetAppId(),
+      base::BindOnce(
+          &ExtensionAppShimHandler::OnShimSelectedProfileAndAppLoaded,
+          weak_factory_.GetWeakPtr()));
+}
+
+void ExtensionAppShimHandler::OnShimSelectedProfileAndAppLoaded(
+    Profile* profile,
+    const extensions::Extension* extension) {
+  if (!extension)
+    return;
+
+  auto found_app = apps_.find(extension->id());
+  if (found_app == apps_.end())
+    return;
+  AppState* app_state = found_app->second.get();
+  auto found_profile = app_state->profiles.find(profile);
+  if (found_profile != app_state->profiles.end()) {
+    // If this profile is currently open for the app, focus its windows.
+    ProfileState* profile_state = found_profile->second.get();
+    for (auto* browser : profile_state->browsers) {
+      if (auto* window = browser->window())
+        window->Show();
+    }
+  } else {
+    // Otherwise, launch the app for this profile (which will open a new
+    // window).
+    delegate_->LaunchApp(profile, extension, std::vector<base::FilePath>());
+  }
 }
 
 void ExtensionAppShimHandler::set_delegate(Delegate* delegate) {
@@ -847,6 +892,7 @@
   if (!avatar_menu_)
     return;
   avatar_menu_->ActiveBrowserChanged(browser);
+  avatar_menu_->RebuildMenu();
   for (auto& iter_app : apps_) {
     AppState* app_state = iter_app.second.get();
     if (app_state->IsMultiProfile())
@@ -903,27 +949,32 @@
   const bool is_multi_profile =
       base::FeatureList::IsEnabled(features::kAppShimMultiProfile) &&
       extension->from_bookmark();
+  const base::FilePath profile_path =
+      is_multi_profile ? base::FilePath() : profile->GetPath();
+  const std::string app_id = extension->id();
+  const bool use_remote_cocoa = UsesRemoteViews(extension);
 
   auto found_app = apps_.find(extension->id());
   if (found_app == apps_.end()) {
     std::unique_ptr<AppShimHost> multi_profile_host;
-    // TODO(https://crbug.com/982024): Pass nullptr instead of |profile| to
-    // CreateHost.
-    if (is_multi_profile)
-      multi_profile_host = delegate_->CreateHost(this, profile, extension);
+    if (is_multi_profile) {
+      multi_profile_host =
+          delegate_->CreateHost(this, profile_path, app_id, use_remote_cocoa);
+    }
     auto new_app_state =
         std::make_unique<AppState>(std::move(multi_profile_host));
     found_app =
-        apps_.insert(std::make_pair(extension->id(), std::move(new_app_state)))
-            .first;
+        apps_.insert(std::make_pair(app_id, std::move(new_app_state))).first;
   }
   AppState* app_state = found_app->second.get();
 
   auto found_profile = app_state->profiles.find(profile);
   if (found_profile == app_state->profiles.end()) {
     std::unique_ptr<AppShimHost> single_profile_host;
-    if (!is_multi_profile)
-      single_profile_host = delegate_->CreateHost(this, profile, extension);
+    if (!is_multi_profile) {
+      single_profile_host =
+          delegate_->CreateHost(this, profile_path, app_id, use_remote_cocoa);
+    }
     auto new_profile_state = std::make_unique<ProfileState>(
         app_state, std::move(single_profile_host));
     found_profile =
diff --git a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h
index 695050c..a2abdf8 100644
--- a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h
+++ b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac.h
@@ -54,42 +54,68 @@
    public:
     virtual ~Delegate() {}
 
+    // Create an avatar menu (disable-able for tests).
     virtual std::unique_ptr<AvatarMenu> CreateAvatarMenu(
         AvatarMenuObserver* observer);
-    virtual base::FilePath GetFullProfilePath(
-        const base::FilePath& relative_path);
-    virtual bool ProfileExistsForPath(const base::FilePath& path);
+
+    // Return the profile for |path|, only if it is already loaded.
     virtual Profile* ProfileForPath(const base::FilePath& path);
+
+    // Load a profile and call |callback| when completed or failed.
     virtual void LoadProfileAsync(const base::FilePath& path,
                                   base::OnceCallback<void(Profile*)> callback);
+
+    // Return true if the specified path is for a valid profile that is also
+    // locked.
     virtual bool IsProfileLockedForPath(const base::FilePath& path);
 
+    // Return the app windows (not browser windows) for a legacy app.
     virtual extensions::AppWindowRegistry::AppWindowList GetWindows(
         Profile* profile,
         const std::string& extension_id);
 
+    // Look up an extension from its id.
     virtual const extensions::Extension* MaybeGetAppExtension(
         content::BrowserContext* context,
         const std::string& extension_id);
+
+    // Return true if the specified app should use an app shim (false, e.g, for
+    // bookmark apps that open in tabs).
     virtual bool AllowShimToConnect(Profile* profile,
                                     const extensions::Extension* extension);
+
+    // Create an AppShimHost for the specified parameters (intercept-able for
+    // tests).
     virtual std::unique_ptr<AppShimHost> CreateHost(
         AppShimHost::Client* client,
-        Profile* profile,
-        const extensions::Extension* extension);
+        const base::FilePath& profile_path,
+        const std::string& app_id,
+        bool use_remote_cocoa);
+
+    // Open a dialog to enable the specified extension. Call |callback| after
+    // the dialog is executed.
     virtual void EnableExtension(Profile* profile,
                                  const std::string& extension_id,
                                  base::OnceCallback<void()> callback);
+
+    // Launch the app in Chrome. This will (often) create a new window.
     virtual void LaunchApp(Profile* profile,
                            const extensions::Extension* extension,
                            const std::vector<base::FilePath>& files);
+
+    // Launch the shim process for an app.
     virtual void LaunchShim(Profile* profile,
                             const extensions::Extension* extension,
                             bool recreate_shims,
                             ShimLaunchedCallback launched_callback,
                             ShimTerminatedCallback terminated_callback);
+
+    // Launch the user manager (in response to attempting to access a locked
+    // profile).
     virtual void LaunchUserManager();
 
+    // Terminate Chrome if Chrome attempted to quit, but was prevented from
+    // quitting due to apps being open.
     virtual void MaybeTerminate();
   };
 
@@ -182,14 +208,31 @@
   // Close one specified app.
   void CloseShimForApp(Profile* profile, const std::string& app_id);
 
-  // This is passed to Delegate::LoadProfileAsync for shim-initiated launches
-  // where the profile was not yet loaded.
-  void OnProfileLoaded(std::unique_ptr<AppShimHostBootstrap> bootstrap,
-                       Profile* profile);
+  // Continuation of OnShimProcessConnected, once the profile has loaded.
+  void OnShimProcessConnectedAndAppLoaded(
+      std::unique_ptr<AppShimHostBootstrap> bootstrap,
+      Profile* profile,
+      const extensions::Extension* extension);
 
-  // This is passed to Delegate::EnableViaPrompt for shim-initiated launches
-  // where the extension is disabled.
-  void OnExtensionEnabled(std::unique_ptr<AppShimHostBootstrap> bootstrap);
+  // Continuation of OnShimSelectedProfile, once the profile has loaded.
+  void OnShimSelectedProfileAndAppLoaded(
+      Profile* profile,
+      const extensions::Extension* extension);
+
+  // Load the specified profile and extension, and run |callback| with
+  // the result. The callback's arguments may be nullptr on failure.
+  using LoadProfileAppCallback =
+      base::OnceCallback<void(Profile*, const extensions::Extension*)>;
+  void LoadProfileAndApp(const base::FilePath& profile_path,
+                         const std::string& app_id,
+                         LoadProfileAppCallback callback);
+  void OnProfileLoaded(const base::FilePath& profile_path,
+                       const std::string& app_id,
+                       LoadProfileAppCallback callback,
+                       Profile* profile);
+  void OnAppEnabled(const base::FilePath& profile_path,
+                    const std::string& app_id,
+                    LoadProfileAppCallback callback);
 
   // Update the profiles menu for the specified host.
   void UpdateHostProfileMenu(AppShimHost* host);
diff --git a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac_unittest.cc b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac_unittest.cc
index 9fa6173..1589815 100644
--- a/chrome/browser/apps/app_shim/extension_app_shim_handler_mac_unittest.cc
+++ b/chrome/browser/apps/app_shim/extension_app_shim_handler_mac_unittest.cc
@@ -52,7 +52,6 @@
   base::FilePath GetFullProfilePath(const base::FilePath& relative_path) {
     return relative_path;
   }
-  MOCK_METHOD1(ProfileExistsForPath, bool(const base::FilePath&));
   MOCK_METHOD1(ProfileForPath, Profile*(const base::FilePath&));
   void LoadProfileAsync(const base::FilePath& path,
                         base::OnceCallback<void(Profile*)> callback) override {
@@ -113,10 +112,10 @@
   void SetHostForCreate(std::unique_ptr<AppShimHost> host_for_create) {
     host_for_create_ = std::move(host_for_create);
   }
-  std::unique_ptr<AppShimHost> CreateHost(
-      AppShimHost::Client* client,
-      Profile* profile,
-      const extensions::Extension* extension) override {
+  std::unique_ptr<AppShimHost> CreateHost(AppShimHost::Client* client,
+                                          const base::FilePath& profile_path,
+                                          const std::string& app_id,
+                                          bool use_remote_cocoa) override {
     DCHECK(host_for_create_);
     std::unique_ptr<AppShimHost> result = std::move(host_for_create_);
     return result;
@@ -179,10 +178,12 @@
   TestingAppShimHostBootstrap(
       const base::FilePath& profile_path,
       const std::string& app_id,
+      bool is_from_bookmark,
       base::Optional<apps::AppShimLaunchResult>* launch_result)
       : AppShimHostBootstrap(getpid()),
         profile_path_(profile_path),
         app_id_(app_id),
+        is_from_bookmark_(is_from_bookmark),
         launch_result_(launch_result),
         weak_factory_(this) {}
   void DoTestLaunch(apps::AppShimLaunchType launch_type,
@@ -191,7 +192,8 @@
     auto app_shim_info = chrome::mojom::AppShimInfo::New();
     app_shim_info->profile_path = profile_path_;
     app_shim_info->app_id = app_id_;
-    app_shim_info->app_url = GURL("https://example.com");
+    if (is_from_bookmark_)
+      app_shim_info->app_url = GURL("https://example.com");
     app_shim_info->launch_type = launch_type;
     app_shim_info->files = files;
     OnShimConnected(
@@ -213,8 +215,9 @@
   }
 
  private:
-  base::FilePath profile_path_;
-  std::string app_id_;
+  const base::FilePath profile_path_;
+  const std::string app_id_;
+  const bool is_from_bookmark_;
   // Note that |launch_result_| is optional so that we can track whether or not
   // the callback to set it has arrived.
   base::Optional<apps::AppShimLaunchResult>* launch_result_;
@@ -250,6 +253,8 @@
     return test_weak_factory_.GetWeakPtr();
   }
 
+  using AppShimHost::ProfileSelectedFromMenu;
+
  private:
   bool did_connect_to_host_ = false;
 
@@ -266,20 +271,25 @@
         profile_path_b_("Profile B") {
     AppShimHostBootstrap::SetClient(handler_.get());
     bootstrap_aa_ = (new TestingAppShimHostBootstrap(
-                         profile_path_a_, kTestAppIdA, &bootstrap_aa_result_))
+                         profile_path_a_, kTestAppIdA,
+                         true /* is_from_bookmark */, &bootstrap_aa_result_))
                         ->GetWeakPtr();
     bootstrap_ab_ = (new TestingAppShimHostBootstrap(
-                         profile_path_a_, kTestAppIdB, &bootstrap_ab_result_))
+                         profile_path_a_, kTestAppIdB,
+                         false /* is_from_bookmark */, &bootstrap_ab_result_))
                         ->GetWeakPtr();
     bootstrap_bb_ = (new TestingAppShimHostBootstrap(
-                         profile_path_b_, kTestAppIdB, &bootstrap_bb_result_))
+                         profile_path_b_, kTestAppIdB,
+                         false /* is_from_bookmark */, &bootstrap_bb_result_))
                         ->GetWeakPtr();
     bootstrap_aa_duplicate_ =
         (new TestingAppShimHostBootstrap(profile_path_a_, kTestAppIdA,
+                                         true /* is_from_bookmark */,
                                          &bootstrap_aa_duplicate_result_))
             ->GetWeakPtr();
     bootstrap_aa_thethird_ =
         (new TestingAppShimHostBootstrap(profile_path_a_, kTestAppIdA,
+                                         true /* is_from_bookmark */,
                                          &bootstrap_aa_thethird_result_))
             ->GetWeakPtr();
 
@@ -314,14 +324,10 @@
                        .SetID(kTestAppIdB)
                        .Build();
 
-    EXPECT_CALL(*delegate_, ProfileExistsForPath(profile_path_a_))
-        .WillRepeatedly(Return(true));
     EXPECT_CALL(*delegate_, IsProfileLockedForPath(profile_path_a_))
         .WillRepeatedly(Return(false));
     EXPECT_CALL(*delegate_, ProfileForPath(profile_path_a_))
         .WillRepeatedly(Return(&profile_a_));
-    EXPECT_CALL(*delegate_, ProfileExistsForPath(profile_path_b_))
-        .WillRepeatedly(Return(true));
     EXPECT_CALL(*delegate_, IsProfileLockedForPath(profile_path_b_))
         .WillRepeatedly(Return(false));
     EXPECT_CALL(*delegate_, ProfileForPath(profile_path_b_))
@@ -448,10 +454,10 @@
 
 TEST_F(ExtensionAppShimHandlerTest, LaunchProfileNotFound) {
   // Bad profile path.
-  EXPECT_CALL(*delegate_, ProfileExistsForPath(profile_path_a_))
-      .WillOnce(Return(false))
-      .WillRepeatedly(Return(true));
+  EXPECT_CALL(*delegate_, ProfileForPath(profile_path_a_))
+      .WillRepeatedly(Return(static_cast<Profile*>(nullptr)));
   NormalLaunch(bootstrap_aa_, nullptr);
+  delegate_->RunLoadProfileCallback(profile_path_a_, nullptr);
   EXPECT_EQ(APP_SHIM_LAUNCH_PROFILE_NOT_FOUND, *bootstrap_aa_result_);
 }
 
@@ -821,4 +827,77 @@
   }
 }
 
+TEST_F(ExtensionAppShimHandlerTest, MultiProfileShimLaunch) {
+  base::test::ScopedFeatureList scoped_features;
+  scoped_features.InitWithFeatures(
+      /*enabled_features=*/{features::kAppShimMultiProfile},
+      /*disabled_features=*/{});
+
+  delegate_->SetHostForCreate(std::move(host_aa_unique_));
+  ShimLaunchedCallback launched_callback;
+  delegate_->SetCaptureShimLaunchedCallback(&launched_callback);
+  ShimTerminatedCallback terminated_callback;
+  delegate_->SetCaptureShimTerminatedCallback(&terminated_callback);
+
+  // Launch the app for profile A. This should trigger a shim launch request.
+  EXPECT_CALL(*delegate_, DoLaunchShim(&profile_a_, extension_a_.get(),
+                                       false /* recreate_shim */));
+  EXPECT_EQ(nullptr, handler_->FindHost(&profile_a_, kTestAppIdA));
+  handler_->OnAppActivated(&profile_a_, kTestAppIdA);
+  EXPECT_EQ(host_aa_.get(), handler_->FindHost(&profile_a_, kTestAppIdA));
+  EXPECT_FALSE(host_aa_->did_connect_to_host());
+
+  // Launch the app for profile B. This should not cause a shim launch request.
+  EXPECT_CALL(*delegate_, DoLaunchShim(_, _, _)).Times(0);
+  handler_->OnAppActivated(&profile_b_, kTestAppIdA);
+
+  // Indicate the profile A that its launch succeeded.
+  EXPECT_TRUE(launched_callback);
+  EXPECT_TRUE(terminated_callback);
+  std::move(launched_callback).Run(base::Process(5));
+  EXPECT_FALSE(launched_callback);
+  EXPECT_TRUE(terminated_callback);
+}
+
+TEST_F(ExtensionAppShimHandlerTest, MultiProfileSelectMenu) {
+  base::test::ScopedFeatureList scoped_features;
+  scoped_features.InitWithFeatures(
+      /*enabled_features=*/{features::kAppShimMultiProfile},
+      /*disabled_features=*/{});
+
+  delegate_->SetHostForCreate(std::move(host_aa_unique_));
+  ShimLaunchedCallback launched_callback;
+  delegate_->SetCaptureShimLaunchedCallback(&launched_callback);
+  ShimTerminatedCallback terminated_callback;
+  delegate_->SetCaptureShimTerminatedCallback(&terminated_callback);
+
+  // Launch the app for profile A. This should trigger a shim launch request.
+  EXPECT_CALL(*delegate_, DoLaunchShim(&profile_a_, extension_a_.get(),
+                                       false /* recreate_shim */));
+  EXPECT_EQ(nullptr, handler_->FindHost(&profile_a_, kTestAppIdA));
+  handler_->OnAppActivated(&profile_a_, kTestAppIdA);
+  EXPECT_EQ(host_aa_.get(), handler_->FindHost(&profile_a_, kTestAppIdA));
+  EXPECT_FALSE(host_aa_->did_connect_to_host());
+
+  // Indicate the profile A that its launch succeeded.
+  EXPECT_TRUE(launched_callback);
+  EXPECT_TRUE(terminated_callback);
+  std::move(launched_callback).Run(base::Process(5));
+  EXPECT_FALSE(launched_callback);
+  EXPECT_TRUE(terminated_callback);
+
+  // Select profile B from the menu. This should request that the app be
+  // launched.
+  EXPECT_CALL(*delegate_, LaunchApp(&profile_b_, extension_a_.get(), _));
+  host_aa_->ProfileSelectedFromMenu(profile_path_b_);
+  EXPECT_CALL(*delegate_, DoLaunchShim(_, _, _)).Times(0);
+  handler_->OnAppActivated(&profile_b_, kTestAppIdA);
+
+  // Select profile A and B from the menu -- this should not request a launch,
+  // because the profiles are already enabled.
+  EXPECT_CALL(*delegate_, LaunchApp(_, _, _)).Times(0);
+  host_aa_->ProfileSelectedFromMenu(profile_path_a_);
+  host_aa_->ProfileSelectedFromMenu(profile_path_b_);
+}
+
 }  // namespace apps
diff --git a/chrome/browser/autocomplete/search_provider_unittest.cc b/chrome/browser/autocomplete/search_provider_unittest.cc
index ffffb43..1a82c6a 100644
--- a/chrome/browser/autocomplete/search_provider_unittest.cc
+++ b/chrome/browser/autocomplete/search_provider_unittest.cc
@@ -3531,12 +3531,12 @@
   EXPECT_FALSE(provider_->deletion_handlers_.empty());
   ASSERT_TRUE(test_url_loader_factory_.IsPending(kDeleteUrl));
 
-  network::ResourceResponseHead head;
+  auto head = network::mojom::URLResponseHead::New();
   std::string headers("HTTP/1.1 500 Owiee\nContent-type: application/json\n\n");
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
       net::HttpUtil::AssembleRawHeaders(headers));
-  head.mime_type = "application/json";
-  test_url_loader_factory_.AddResponse(GURL(kDeleteUrl), head, "",
+  head->mime_type = "application/json";
+  test_url_loader_factory_.AddResponse(GURL(kDeleteUrl), std::move(head), "",
                                        network::URLLoaderCompletionStatus());
 
   profile_.BlockUntilHistoryProcessesPendingRequests();
diff --git a/chrome/browser/availability/availability_prober_unittest.cc b/chrome/browser/availability/availability_prober_unittest.cc
index 0a35827..99040e4 100644
--- a/chrome/browser/availability/availability_prober_unittest.cc
+++ b/chrome/browser/availability/availability_prober_unittest.cc
@@ -150,11 +150,10 @@
     ASSERT_EQ(request->request.url.host(), kTestUrl.host());
     ASSERT_EQ(request->request.url.scheme(), kTestUrl.scheme());
 
-    network::ResourceResponseHead head =
-        network::CreateResourceResponseHead(http_status);
+    auto head = network::CreateURLResponseHead(http_status);
     network::URLLoaderCompletionStatus status(net_error);
-    test_url_loader_factory_.AddResponse(request->request.url, head, "content",
-                                         status);
+    test_url_loader_factory_.AddResponse(request->request.url, std::move(head),
+                                         "content", status);
     RunUntilIdle();
     // Clear responses in the network service so we can inspect the next request
     // that comes in before it is responded to.
diff --git a/chrome/browser/banners/app_banner_manager.cc b/chrome/browser/banners/app_banner_manager.cc
index 76067de..b86b5e4 100644
--- a/chrome/browser/banners/app_banner_manager.cc
+++ b/chrome/browser/banners/app_banner_manager.cc
@@ -47,16 +47,6 @@
 
 namespace banners {
 
-AppBannerManager::Observer::Observer() = default;
-AppBannerManager::Observer::~Observer() = default;
-
-void AppBannerManager::Observer::ObserveAppBannerManager(
-    AppBannerManager* manager) {
-  scoped_observer_.RemoveAll();
-  if (manager)
-    scoped_observer_.Add(manager);
-}
-
 // static
 base::Time AppBannerManager::GetCurrentTime() {
   return base::Time::Now() +
@@ -216,7 +206,7 @@
     content::WebContents* web_contents) {
   AppBannerManager* existing_manager = FromWebContents(web_contents);
   for (Observer& observer : existing_manager->observer_list_)
-    observer.ObserveAppBannerManager(this);
+    observer.OnAppBannerManagerChanged(this);
   DCHECK(existing_manager->observer_list_.begin() ==
          existing_manager->observer_list_.end())
       << "Old observer list must be empty after transfer to test instance.";
@@ -248,11 +238,7 @@
   AppBannerSettingsHelper::UpdateFromFieldTrial();
 }
 
-AppBannerManager::~AppBannerManager() {
-  for (Observer& observer : observer_list_)
-    observer.ObserveAppBannerManager(nullptr);
-  CHECK(!observer_list_.might_have_observers());
-}
+AppBannerManager::~AppBannerManager() = default;
 
 bool AppBannerManager::CheckIfShouldShowBanner() {
   if (ShouldBypassEngagementChecks())
diff --git a/chrome/browser/banners/app_banner_manager.h b/chrome/browser/banners/app_banner_manager.h
index 9e9a3ad..8b7c31e 100644
--- a/chrome/browser/banners/app_banner_manager.h
+++ b/chrome/browser/banners/app_banner_manager.h
@@ -12,7 +12,6 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "base/observer_list.h"
-#include "base/scoped_observer.h"
 #include "base/strings/string16.h"
 #include "chrome/browser/engagement/site_engagement_observer.h"
 #include "chrome/browser/installable/installable_logging.h"
@@ -53,15 +52,8 @@
  public:
   class Observer : public base::CheckedObserver {
    public:
-    Observer();
-    ~Observer() override;
-
-    void ObserveAppBannerManager(AppBannerManager* manager);
-
+    virtual void OnAppBannerManagerChanged(AppBannerManager* new_manager) = 0;
     virtual void OnInstallableWebAppStatusUpdated() = 0;
-
-   private:
-    ScopedObserver<AppBannerManager, Observer> scoped_observer_{this};
   };
 
   // A StatusReporter handles the reporting of |InstallableStatusCode|s.
diff --git a/chrome/browser/chrome_content_browser_client.cc b/chrome/browser/chrome_content_browser_client.cc
index 0bff08b..49443d7 100644
--- a/chrome/browser/chrome_content_browser_client.cc
+++ b/chrome/browser/chrome_content_browser_client.cc
@@ -1097,10 +1097,7 @@
 
 ChromeContentBrowserClient::ChromeContentBrowserClient(
     StartupData* startup_data)
-    : data_reduction_proxy_throttle_manager_(
-          nullptr,
-          base::OnTaskRunnerDeleter(nullptr)),
-      startup_data_(startup_data) {
+    : startup_data_(startup_data) {
 #if BUILDFLAG(ENABLE_PLUGINS)
   for (size_t i = 0; i < base::size(kPredefinedAllowedDevChannelOrigins); ++i)
     allowed_dev_channel_origins_.insert(kPredefinedAllowedDevChannelOrigins[i]);
@@ -4535,16 +4532,13 @@
       data_reduction_proxy::params::IsEnabledWithNetworkService() &&
       drp_settings) {
     if (!data_reduction_proxy_throttle_manager_) {
-      data_reduction_proxy_throttle_manager_ = std::unique_ptr<
-          data_reduction_proxy::DataReductionProxyThrottleManager,
-          base::OnTaskRunnerDeleter>(
-          new data_reduction_proxy::DataReductionProxyThrottleManager(
-              drp_settings->data_reduction_proxy_service(),
-              data_reduction_proxy::DataReductionProxyThrottleManager::
-                  CreateConfig(drp_settings->data_reduction_proxy_service()
-                                   ->config()
-                                   ->GetProxiesForHttp())),
-          base::OnTaskRunnerDeleter(base::SequencedTaskRunnerHandle::Get()));
+      data_reduction_proxy_throttle_manager_ = std::make_unique<
+          data_reduction_proxy::DataReductionProxyThrottleManager>(
+          drp_settings->data_reduction_proxy_service(),
+          data_reduction_proxy::DataReductionProxyThrottleManager::CreateConfig(
+              drp_settings->data_reduction_proxy_service()
+                  ->config()
+                  ->GetProxiesForHttp()));
     }
     net::HttpRequestHeaders headers;
     data_reduction_proxy::DataReductionProxyRequestOptions::
diff --git a/chrome/browser/chrome_content_browser_client.h b/chrome/browser/chrome_content_browser_client.h
index b080144..b037cff 100644
--- a/chrome/browser/chrome_content_browser_client.h
+++ b/chrome/browser/chrome_content_browser_client.h
@@ -18,7 +18,6 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "base/sequenced_task_runner.h"
 #include "build/build_config.h"
 #include "chrome/browser/startup_data.h"
 #include "content/public/browser/content_browser_client.h"
@@ -692,8 +691,7 @@
   scoped_refptr<safe_browsing::UrlCheckerDelegate>
       safe_browsing_url_checker_delegate_;
 
-  std::unique_ptr<data_reduction_proxy::DataReductionProxyThrottleManager,
-                  base::OnTaskRunnerDeleter>
+  std::unique_ptr<data_reduction_proxy::DataReductionProxyThrottleManager>
       data_reduction_proxy_throttle_manager_;
 
   std::unique_ptr<service_manager::BinderRegistry> frame_interfaces_;
diff --git a/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc b/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc
index 3ba52aa..432dcbb 100644
--- a/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc
+++ b/chrome/browser/chromeos/arc/auth/arc_active_directory_enrollment_token_fetcher_browsertest.cc
@@ -432,15 +432,15 @@
 
   test_url_loader_factory_.SetInterceptor(
       base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
-        network::ResourceResponseHead head;
+        auto head = network::mojom::URLResponseHead::New();
         std::string status_line("HTTP/1.1 904 ARC Disabled");
         std::string headers = status_line + "\nContent-type: text/html\n\n";
-        head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+        head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
             net::HttpUtil::AssembleRawHeaders(headers));
         network::URLLoaderCompletionStatus status;
 
-        test_url_loader_factory_.AddResponse(request.url, head, std::string(),
-                                             status);
+        test_url_loader_factory_.AddResponse(request.url, std::move(head),
+                                             std::string(), status);
       }));
   base::RunLoop run_loop;
   ExpectEnrollmentTokenFetchFails(&run_loop, Status::ARC_DISABLED);
diff --git a/chrome/browser/chromeos/attestation/attestation_ca_client_unittest.cc b/chrome/browser/chromeos/attestation/attestation_ca_client_unittest.cc
index 22e2cc2..dba7ac7 100644
--- a/chrome/browser/chromeos/attestation/attestation_ca_client_unittest.cc
+++ b/chrome/browser/chromeos/attestation/attestation_ca_client_unittest.cc
@@ -70,14 +70,13 @@
 
   void SendResponse(net::Error error, net::HttpStatusCode response_code) {
     CHECK(test_url_loader_factory_.NumPending() == 1);
-    auto resource_response_head =
-        network::CreateResourceResponseHead(response_code);
+    auto url_response_head = network::CreateURLResponseHead(response_code);
     network::URLLoaderCompletionStatus completion_status(error);
     std::string response =
         network::GetUploadData(last_resource_request_) + "_response";
 
     test_url_loader_factory_.AddResponse(last_resource_request_.url,
-                                         resource_response_head, response,
+                                         std::move(url_response_head), response,
                                          completion_status);
     base::RunLoop().RunUntilIdle();
   }
diff --git a/chrome/browser/chromeos/bluetooth/debug_logs_manager.cc b/chrome/browser/chromeos/bluetooth/debug_logs_manager.cc
index 1b400ff..ceb225ed 100644
--- a/chrome/browser/chromeos/bluetooth/debug_logs_manager.cc
+++ b/chrome/browser/chromeos/bluetooth/debug_logs_manager.cc
@@ -9,6 +9,10 @@
 #include "chromeos/constants/chromeos_features.h"
 #include "components/user_manager/user.h"
 
+namespace chromeos {
+
+namespace bluetooth {
+
 namespace {
 const char kSupportedEmailSuffix[] = "@google.com";
 }  // namespace
@@ -51,3 +55,7 @@
   return base::EndsWith(primary_user_->GetDisplayEmail(), kSupportedEmailSuffix,
                         base::CompareCase::INSENSITIVE_ASCII);
 }
+
+}  // namespace bluetooth
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/bluetooth/debug_logs_manager.h b/chrome/browser/chromeos/bluetooth/debug_logs_manager.h
index 6509242..4c6cefc 100644
--- a/chrome/browser/chromeos/bluetooth/debug_logs_manager.h
+++ b/chrome/browser/chromeos/bluetooth/debug_logs_manager.h
@@ -13,6 +13,10 @@
 class User;
 }  // namespace user_manager
 
+namespace chromeos {
+
+namespace bluetooth {
+
 // Manages the use of debug Bluetooth logs. Under normal usage, only warning and
 // error logs are captured, but there are some situations in which it is
 // advantageous to capture more verbose logs (e.g., in noisy environments or on
@@ -51,4 +55,8 @@
   DISALLOW_COPY_AND_ASSIGN(DebugLogsManager);
 };
 
+}  // namespace bluetooth
+
+}  // namespace chromeos
+
 #endif  // CHROME_BROWSER_CHROMEOS_BLUETOOTH_DEBUG_LOGS_MANAGER_H_
diff --git a/chrome/browser/chromeos/bluetooth/debug_logs_manager_factory.cc b/chrome/browser/chromeos/bluetooth/debug_logs_manager_factory.cc
index ae31084..1742217 100644
--- a/chrome/browser/chromeos/bluetooth/debug_logs_manager_factory.cc
+++ b/chrome/browser/chromeos/bluetooth/debug_logs_manager_factory.cc
@@ -8,10 +8,15 @@
 #include "chrome/browser/chromeos/bluetooth/debug_logs_manager.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/signin/identity_manager_factory.h"
 #include "components/keyed_service/content/browser_context_dependency_manager.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 #include "components/keyed_service/core/keyed_service.h"
 
+namespace chromeos {
+
+namespace bluetooth {
+
 namespace {
 
 // Wraps a DebugLogsManager instance in a KeyedService.
@@ -51,7 +56,9 @@
 DebugLogsManagerFactory::DebugLogsManagerFactory()
     : BrowserContextKeyedServiceFactory(
           "DebugLogsManagerFactory",
-          BrowserContextDependencyManager::GetInstance()) {}
+          BrowserContextDependencyManager::GetInstance()) {
+  DependsOn(IdentityManagerFactory::GetInstance());
+}
 
 DebugLogsManagerFactory::~DebugLogsManagerFactory() = default;
 
@@ -69,3 +76,7 @@
 bool DebugLogsManagerFactory::ServiceIsCreatedWithBrowserContext() const {
   return true;
 }
+
+}  // namespace bluetooth
+
+}  // namespace chromeos
diff --git a/chrome/browser/chromeos/bluetooth/debug_logs_manager_factory.h b/chrome/browser/chromeos/bluetooth/debug_logs_manager_factory.h
index 2c343db..4201f5c 100644
--- a/chrome/browser/chromeos/bluetooth/debug_logs_manager_factory.h
+++ b/chrome/browser/chromeos/bluetooth/debug_logs_manager_factory.h
@@ -8,9 +8,14 @@
 #include "base/memory/singleton.h"
 #include "components/keyed_service/content/browser_context_keyed_service_factory.h"
 
-class DebugLogsManager;
 class Profile;
 
+namespace chromeos {
+
+namespace bluetooth {
+
+class DebugLogsManager;
+
 // Factory for DebugLogsManager.
 class DebugLogsManagerFactory : public BrowserContextKeyedServiceFactory {
  public:
@@ -31,4 +36,8 @@
   DISALLOW_COPY_AND_ASSIGN(DebugLogsManagerFactory);
 };
 
+}  // namespace bluetooth
+
+}  // namespace chromeos
+
 #endif  // CHROME_BROWSER_CHROMEOS_BLUETOOTH_DEBUG_LOGS_MANAGER_FACTORY_H_
diff --git a/chrome/browser/chromeos/customization/customization_document_unittest.cc b/chrome/browser/chromeos/customization/customization_document_unittest.cc
index 920c17a..4f533aa 100644
--- a/chrome/browser/chromeos/customization/customization_document_unittest.cc
+++ b/chrome/browser/chromeos/customization/customization_document_unittest.cc
@@ -252,10 +252,10 @@
     GURL url(base::StringPrintf(ServicesCustomizationDocument::kManifestUrl,
                                 id.c_str()));
 
-    network::ResourceResponseHead response_head;
-    response_head.headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
-    response_head.headers->AddHeader("Content-Type: application/json");
-    loader_factory_.AddResponse(url, response_head, manifest,
+    auto response_head = network::mojom::URLResponseHead::New();
+    response_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+    response_head->headers->AddHeader("Content-Type: application/json");
+    loader_factory_.AddResponse(url, std::move(response_head), manifest,
                                 network::URLLoaderCompletionStatus(net::OK));
     EXPECT_CALL(*interceptor_, Intercept).Times(Exactly(1));
   }
@@ -264,11 +264,11 @@
     GURL url(base::StringPrintf(ServicesCustomizationDocument::kManifestUrl,
                                 id.c_str()));
 
-    network::ResourceResponseHead response_head;
-    response_head.headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
-    response_head.headers->AddHeader("Content-Type: application/json");
-    response_head.headers->ReplaceStatusLine("HTTP/1.1 404 Not found");
-    loader_factory_.AddResponse(url, response_head, std::string(),
+    auto response_head = network::mojom::URLResponseHead::New();
+    response_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+    response_head->headers->AddHeader("Content-Type: application/json");
+    response_head->headers->ReplaceStatusLine("HTTP/1.1 404 Not found");
+    loader_factory_.AddResponse(url, std::move(response_head), std::string(),
                                 network::URLLoaderCompletionStatus(net::OK));
     EXPECT_CALL(*interceptor_, Intercept).Times(Exactly(1));
   }
diff --git a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
index c8eccc0..57e283d 100644
--- a/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
+++ b/chrome/browser/chromeos/extensions/autotest_private/autotest_private_api.cc
@@ -15,7 +15,6 @@
 #include "ash/public/cpp/shelf_model.h"
 #include "ash/public/cpp/shelf_prefs.h"
 #include "ash/public/cpp/shelf_types.h"
-#include "ash/public/cpp/split_view.h"
 #include "ash/public/cpp/split_view_test_api.h"
 #include "ash/public/cpp/tablet_mode.h"
 #include "ash/public/cpp/window_properties.h"
diff --git a/chrome/browser/chromeos/fileapi/external_file_url_loader_factory_unittest.cc b/chrome/browser/chromeos/fileapi/external_file_url_loader_factory_unittest.cc
index c21d227..8027ec42 100644
--- a/chrome/browser/chromeos/fileapi/external_file_url_loader_factory_unittest.cc
+++ b/chrome/browser/chromeos/fileapi/external_file_url_loader_factory_unittest.cc
@@ -180,7 +180,7 @@
   client.RunUntilComplete();
 
   ASSERT_EQ(net::OK, client.completion_status().error_code);
-  EXPECT_EQ("text/plain", client.response_head().mime_type);
+  EXPECT_EQ("text/plain", client.response_head()->mime_type);
   std::string response_body;
   ASSERT_TRUE(mojo::BlockingCopyToString(client.response_body_release(),
                                          &response_body));
diff --git a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.cc b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.cc
index 480756e..f5336a2 100644
--- a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.cc
+++ b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl.cc
@@ -11,6 +11,7 @@
 #include "base/logging.h"
 #include "base/macros.h"
 #include "base/task/post_task.h"
+#include "base/timer/timer.h"
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/browser_process_platform_part_chromeos.h"
 #include "chrome/browser/chrome_content_browser_client.h"
@@ -53,6 +54,28 @@
 
 namespace {
 
+// Currently InvalidationService sends TRANSIENT_INVALIDATION_ERROR in case if
+// topic failing to register, but at the same time InvalidationService has retry
+// logic. In case if retry is successful and all the topic succeeded to
+// register, InvalidationService sends INVALIDATION_ENABLED. So
+// InvalidationServiceObserver should give InvalidationService a chance to
+// reregister topic, and after some time if INVALIDATION_ENABLED is not being
+// received, manually check with delayed task. If after
+// |kCheckInvalidatorStateDelay|, InvalidationService is still in
+// TRANSIENT_INVALIDATION_ERROR state, disconnect from it and try to reregister
+// all the topics.
+constexpr base::TimeDelta kCheckInvalidatorStateDelay =
+    base::TimeDelta::FromMinutes(3);
+
+// After reregistering all the topics |kTransientErrorDisconnectLimit| number of
+// times, when InvalidationService is failing due to
+// TRANSIENT_INVALIDATION_ERROR, stop disconnecting, and let registered topics
+// to keep being registered and failing topics to keep being failed. This is the
+// best effort behaviour. If |kTransientErrorDisconnectLimit| is too high, at
+// some point Firebase Cloud Message will start throttling register request for
+// this client.
+constexpr int kTransientErrorDisconnectLimit = 3;
+
 invalidation::ProfileInvalidationProvider* GetInvalidationProvider(
     Profile* profile) {
   if (base::FeatureList::IsEnabled(features::kPolicyFcmInvalidations)) {
@@ -96,6 +119,7 @@
   ~InvalidationServiceObserver() override;
 
   invalidation::InvalidationService* GetInvalidationService();
+  void CheckInvalidatorState();
   bool IsServiceConnected() const;
 
   // public syncer::InvalidationHandler:
@@ -109,6 +133,10 @@
   invalidation::InvalidationService* invalidation_service_;
   bool is_service_connected_;
   bool is_observer_ready_;
+  base::OneShotTimer transient_error_retry_timer_;
+
+  // The number of times TRANSIENT_INVALIDATION_ERROR should cause disconnect.
+  int transient_error_disconnect_limit_ = kTransientErrorDisconnectLimit;
 
   DISALLOW_COPY_AND_ASSIGN(InvalidationServiceObserver);
 };
@@ -123,7 +151,7 @@
       is_observer_ready_(false) {
   invalidation_service_->RegisterInvalidationHandler(this);
   is_service_connected_ = invalidation_service->GetInvalidatorState() ==
-      syncer::INVALIDATIONS_ENABLED;
+                          syncer::INVALIDATIONS_ENABLED;
   is_observer_ready_ = true;
 }
 
@@ -145,13 +173,26 @@
 }
 
 void AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver::
-    OnInvalidatorStateChange(syncer::InvalidatorState state) {
-  if (!is_observer_ready_)
+    CheckInvalidatorState() {
+  // Treat TRANSIENT_INVALIDATION_ERROR as an error, and disconnect the service
+  // if connected.
+  DCHECK(is_observer_ready_);
+  DCHECK(invalidation_service_);
+  DCHECK(parent_);
+
+  syncer::InvalidatorState state = invalidation_service_->GetInvalidatorState();
+  bool is_service_connected = (state == syncer::INVALIDATIONS_ENABLED);
+
+  if (is_service_connected_ == is_service_connected)
     return;
 
-  const bool is_service_connected = (state == syncer::INVALIDATIONS_ENABLED);
-  if (is_service_connected == is_service_connected_)
-    return;
+  if (state == syncer::TRANSIENT_INVALIDATION_ERROR) {
+    // Do not cause disconnect if the number of disconnections caused by
+    // TRANSIENT_INVALIDATION_ERROR is more than the limit.
+    if (!transient_error_disconnect_limit_)
+      return;
+    --transient_error_disconnect_limit_;
+  }
 
   is_service_connected_ = is_service_connected;
   if (is_service_connected_)
@@ -161,6 +202,44 @@
 }
 
 void AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver::
+    OnInvalidatorStateChange(syncer::InvalidatorState state) {
+  if (!is_observer_ready_)
+    return;
+
+  // TODO(crbug/1007287): Handle 3 different states of
+  // AffiliatedInvalidationServiceProvider properly.
+  if (is_service_connected_) {
+    // If service is connected, do NOT notify parent in case:
+    //   * state == INVALIDATIONS_ENABLED
+    //   * state == TRANSIENT_INVALIDATION_ERROR, hopefully will be resolved by
+    //     InvalidationService, if not InvalidationService should notify again
+    //     with another more severe state.
+    bool should_notify = (state != syncer::INVALIDATIONS_ENABLED &&
+                          state != syncer::TRANSIENT_INVALIDATION_ERROR);
+
+    if (should_notify) {
+      is_service_connected_ = false;
+      parent_->OnInvalidationServiceDisconnected(invalidation_service_);
+    } else if (state == syncer::TRANSIENT_INVALIDATION_ERROR) {
+      transient_error_retry_timer_.Stop();
+      transient_error_retry_timer_.Start(
+          FROM_HERE, kCheckInvalidatorStateDelay,
+          base::BindOnce(&AffiliatedInvalidationServiceProviderImpl::
+                             InvalidationServiceObserver::CheckInvalidatorState,
+                         base::Unretained(this)));
+    }
+  } else {
+    // If service is disconnected, ONLY notify parent in case:
+    //   * state == INVALIDATIONS_ENABLED
+    bool should_notify = (state == syncer::INVALIDATIONS_ENABLED);
+    if (should_notify) {
+      is_service_connected_ = true;
+      parent_->OnInvalidationServiceConnected(invalidation_service_);
+    }
+  }
+}
+
+void AffiliatedInvalidationServiceProviderImpl::InvalidationServiceObserver::
     OnIncomingInvalidation(
         const syncer::ObjectIdInvalidationMap& invalidation_map) {
 }
diff --git a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc
index bce3c6f..488e5b1 100644
--- a/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc
+++ b/chrome/browser/chromeos/policy/affiliated_invalidation_service_provider_impl_unittest.cc
@@ -493,8 +493,16 @@
   SendInvalidatorStateChangeNotification(
       is_fcm_enabled(), device_invalidation_service_,
       syncer::INVALIDATION_CREDENTIALS_REJECTED);
-  EXPECT_EQ(1, consumer_->GetAndClearInvalidationServiceSetCount());
-  EXPECT_EQ(nullptr, consumer_->GetInvalidationService());
+  if (is_fcm_enabled()) {
+    EXPECT_EQ(1, consumer_->GetAndClearInvalidationServiceSetCount());
+    EXPECT_EQ(nullptr, consumer_->GetInvalidationService());
+  } else {
+    // TiclInvalidationService replaces INVALIDATION_CREDENTIALS_REJECTED with
+    // TRANSIENT_INVALIDATION_ERROR. Which doesn't cause disconnection.
+    EXPECT_EQ(0, consumer_->GetAndClearInvalidationServiceSetCount());
+    EXPECT_EQ(provider_->GetDeviceInvalidationServiceForTest(),
+              consumer_->GetInvalidationService());
+  }
 
   // Verify that the device-global invalidation service still exists.
   EXPECT_TRUE(provider_->GetDeviceInvalidationServiceForTest());
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
index 2aef21a..b6f889fe 100644
--- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos_unittest.cc
@@ -641,7 +641,7 @@
       test_url_loader_factory_.SimulateResponseForPendingRequest(
           GaiaUrls::GetInstance()->oauth2_token_url(),
           network::URLLoaderCompletionStatus(net::OK),
-          network::CreateResourceResponseHead(url_fetcher_response_code_),
+          network::CreateURLResponseHead(url_fetcher_response_code_),
           url_fetcher_response_string_);
     }
 
diff --git a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc
index ac5677b..459ff56 100644
--- a/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc
+++ b/chrome/browser/chromeos/policy/user_cloud_policy_manager_chromeos_unittest.cc
@@ -268,13 +268,12 @@
       GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
 
       network::URLLoaderCompletionStatus ok_completion_status(net::OK);
-      network::ResourceResponseHead ok_response =
-          network::CreateResourceResponseHead(net::HTTP_OK);
+      auto ok_response = network::CreateURLResponseHead(net::HTTP_OK);
       // Issue the access token.
       EXPECT_TRUE(
           test_system_url_loader_factory_.SimulateResponseForPendingRequest(
-              gaia_urls->oauth2_token_url(), ok_completion_status, ok_response,
-              kOAuth2AccessTokenData));
+              gaia_urls->oauth2_token_url(), ok_completion_status,
+              std::move(ok_response), kOAuth2AccessTokenData));
     } else {
       // Since the refresh token is available, IdentityManager was used
       // to request the access token and not UserCloudPolicyTokenForwarder.
@@ -570,7 +569,7 @@
       test_system_url_loader_factory()->SimulateResponseForPendingRequest(
           GaiaUrls::GetInstance()->oauth2_token_url(),
           network::URLLoaderCompletionStatus(net::OK),
-          network::CreateResourceResponseHead(net::HTTP_BAD_REQUEST),
+          network::CreateURLResponseHead(net::HTTP_BAD_REQUEST),
           "Error=BadAuthentication"));
 
   // Server check failed, so profile should not be initialized.
@@ -919,12 +918,11 @@
   // Simulate OAuth token fetch.
   GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
   network::URLLoaderCompletionStatus ok_completion_status(net::OK);
-  network::ResourceResponseHead ok_response =
-      network::CreateResourceResponseHead(net::HTTP_OK);
+  auto ok_response = network::CreateURLResponseHead(net::HTTP_OK);
   EXPECT_TRUE(
       test_system_url_loader_factory()->SimulateResponseForPendingRequest(
-          gaia_urls->oauth2_token_url(), ok_completion_status, ok_response,
-          kOAuth2AccessTokenData));
+          gaia_urls->oauth2_token_url(), ok_completion_status,
+          std::move(ok_response), kOAuth2AccessTokenData));
 
   // Validate that re-registration sends the correct parameters.
   EXPECT_TRUE(register_request.register_request().reregister());
@@ -1009,12 +1007,11 @@
   // Simulate OAuth token fetch.
   GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
   network::URLLoaderCompletionStatus ok_completion_status(net::OK);
-  network::ResourceResponseHead ok_response =
-      network::CreateResourceResponseHead(net::HTTP_OK);
+  auto ok_response = network::CreateURLResponseHead(net::HTTP_OK);
   EXPECT_TRUE(
       test_system_url_loader_factory()->SimulateResponseForPendingRequest(
-          gaia_urls->oauth2_token_url(), ok_completion_status, ok_response,
-          kOAuth2AccessTokenData));
+          gaia_urls->oauth2_token_url(), ok_completion_status,
+          std::move(ok_response), kOAuth2AccessTokenData));
 
   // Validate re-registration state.
   ASSERT_TRUE(reregister_job);
diff --git a/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc b/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc
index 2f32466..e7958de 100644
--- a/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc
+++ b/chrome/browser/chromeos/settings/device_oauth2_token_service_unittest.cc
@@ -193,7 +193,7 @@
   if (test_url_loader_factory_.IsPending(url)) {
     test_url_loader_factory_.SimulateResponseForPendingRequest(
         GURL(url), network::URLLoaderCompletionStatus(net::OK),
-        network::CreateResourceResponseHead(response_code), response_string);
+        network::CreateURLResponseHead(response_code), response_string);
   }
 }
 
diff --git a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service_unittest.cc b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service_unittest.cc
index fb0f3a2..25e9b50 100644
--- a/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service_unittest.cc
+++ b/chrome/browser/chromeos/wilco_dtc_supportd/wilco_dtc_supportd_web_request_service_unittest.cc
@@ -106,11 +106,11 @@
       std::unique_ptr<net::HttpStatusCode> response_status,
       net::Error net_error,
       const std::string& response_body) {
-    network::ResourceResponseHead response_head;
-    if (response_status)
-      response_head = network::CreateResourceResponseHead(*response_status);
+    auto response_head = response_status
+                             ? network::CreateURLResponseHead(*response_status)
+                             : network::mojom::URLResponseHead::New();
     test_url_loader_factory_.AddResponse(
-        GURL(url), response_head, response_body,
+        GURL(url), std::move(response_head), response_body,
         network::URLLoaderCompletionStatus(net_error));
   }
 
diff --git a/chrome/browser/complex_tasks/endpoint_fetcher/endpoint_fetcher_unittest.cc b/chrome/browser/complex_tasks/endpoint_fetcher/endpoint_fetcher_unittest.cc
index 50a66975..0af10b0 100644
--- a/chrome/browser/complex_tasks/endpoint_fetcher/endpoint_fetcher_unittest.cc
+++ b/chrome/browser/complex_tasks/endpoint_fetcher/endpoint_fetcher_unittest.cc
@@ -84,17 +84,17 @@
                        const std::string& response_data,
                        net::HttpStatusCode response_code,
                        net::Error error) {
-    network::ResourceResponseHead head;
+    auto head = network::mojom::URLResponseHead::New();
     std::string headers(base::StringPrintf(
         "HTTP/1.1 %d %s\nContent-type: application/json\n\n",
         static_cast<int>(response_code), GetHttpReasonPhrase(response_code)));
-    head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+    head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
         net::HttpUtil::AssembleRawHeaders(headers));
-    head.mime_type = "application/json";
+    head->mime_type = "application/json";
     network::URLLoaderCompletionStatus status(error);
     status.decoded_body_length = response_data.size();
-    test_url_loader_factory_.AddResponse(request_url, head, response_data,
-                                         status);
+    test_url_loader_factory_.AddResponse(request_url, std::move(head),
+                                         response_data, status);
   }
 
  private:
diff --git a/chrome/browser/dom_distiller/lazy_dom_distiller_service.cc b/chrome/browser/dom_distiller/lazy_dom_distiller_service.cc
index 5f137e1..c9e2a02 100644
--- a/chrome/browser/dom_distiller/lazy_dom_distiller_service.cc
+++ b/chrome/browser/dom_distiller/lazy_dom_distiller_service.cc
@@ -92,14 +92,6 @@
   return instance()->CreateDefaultDistillerPageWithHandle(std::move(handle));
 }
 
-void LazyDomDistillerService::AddObserver(DomDistillerObserver* observer) {
-  instance()->AddObserver(observer);
-}
-
-void LazyDomDistillerService::RemoveObserver(DomDistillerObserver* observer) {
-  instance()->RemoveObserver(observer);
-}
-
 DistilledPagePrefs* LazyDomDistillerService::GetDistilledPagePrefs() {
   return instance()->GetDistilledPagePrefs();
 }
diff --git a/chrome/browser/dom_distiller/lazy_dom_distiller_service.h b/chrome/browser/dom_distiller/lazy_dom_distiller_service.h
index e68c670..97a18f51 100644
--- a/chrome/browser/dom_distiller/lazy_dom_distiller_service.h
+++ b/chrome/browser/dom_distiller/lazy_dom_distiller_service.h
@@ -57,8 +57,6 @@
       const gfx::Size& render_view_size) override;
   std::unique_ptr<DistillerPage> CreateDefaultDistillerPageWithHandle(
       std::unique_ptr<SourcePageHandle> handle) override;
-  void AddObserver(DomDistillerObserver* observer) override;
-  void RemoveObserver(DomDistillerObserver* observer) override;
   DistilledPagePrefs* GetDistilledPagePrefs() override;
 
  private:
diff --git a/chrome/browser/extensions/extension_protocols_unittest.cc b/chrome/browser/extensions/extension_protocols_unittest.cc
index f0eca98..4605976 100644
--- a/chrome/browser/extensions/extension_protocols_unittest.cc
+++ b/chrome/browser/extensions/extension_protocols_unittest.cc
@@ -138,22 +138,22 @@
 // depending on the on test type.
 class GetResult {
  public:
-  GetResult(const network::ResourceResponseHead& response, int result)
-      : resource_response_(response), result_(result) {}
+  GetResult(network::mojom::URLResponseHeadPtr response, int result)
+      : response_(std::move(response)), result_(result) {}
   GetResult(GetResult&& other) : result_(other.result_) {}
   ~GetResult() = default;
 
   std::string GetResponseHeaderByName(const std::string& name) const {
     std::string value;
-    if (resource_response_.headers)
-      resource_response_.headers->GetNormalizedHeader(name, &value);
+    if (response_ && response_->headers)
+      response_->headers->GetNormalizedHeader(name, &value);
     return value;
   }
 
   int result() const { return result_; }
 
  private:
-  const network::ResourceResponseHead resource_response_;
+  network::mojom::URLResponseHeadPtr response_;
   int result_;
 
   DISALLOW_COPY_AND_ASSIGN(GetResult);
@@ -277,7 +277,7 @@
     }
 
     client.RunUntilComplete();
-    return GetResult(client.response_head(),
+    return GetResult(client.response_head().Clone(),
                      client.completion_status().error_code);
   }
 
diff --git a/chrome/browser/extensions/updater/extension_updater_unittest.cc b/chrome/browser/extensions/updater/extension_updater_unittest.cc
index 6931c1ee..63711a1 100644
--- a/chrome/browser/extensions/updater/extension_updater_unittest.cc
+++ b/chrome/browser/extensions/updater/extension_updater_unittest.cc
@@ -1282,8 +1282,7 @@
       // Code 5xx causes ExtensionDownloader to retry.
       helper.test_url_loader_factory().SimulateResponseForPendingRequest(
           request->request.url, network::URLLoaderCompletionStatus(net::OK),
-          network::CreateResourceResponseHead(net::HTTP_INTERNAL_SERVER_ERROR),
-          "");
+          network::CreateURLResponseHead(net::HTTP_INTERNAL_SERVER_ERROR), "");
       RunUntilIdle();
     }
     Mock::VerifyAndClearExpectations(&delegate);
@@ -1307,8 +1306,7 @@
       auto* request = helper.GetPendingRequest(0);
       helper.test_url_loader_factory().SimulateResponseForPendingRequest(
           request->request.url, network::URLLoaderCompletionStatus(net::OK),
-          network::CreateResourceResponseHead(net::HTTP_INTERNAL_SERVER_ERROR),
-          "");
+          network::CreateURLResponseHead(net::HTTP_INTERNAL_SERVER_ERROR), "");
     }
     RunUntilIdle();
 
@@ -1318,7 +1316,7 @@
       auto* request = helper.GetPendingRequest(0);
       helper.test_url_loader_factory().SimulateResponseForPendingRequest(
           request->request.url, network::URLLoaderCompletionStatus(net::OK),
-          network::CreateResourceResponseHead(net::HTTP_BAD_REQUEST), "");
+          network::CreateURLResponseHead(net::HTTP_BAD_REQUEST), "");
     }
     RunUntilIdle();
 
diff --git a/chrome/browser/flag-metadata.json b/chrome/browser/flag-metadata.json
index 212041d..172ebc5 100644
--- a/chrome/browser/flag-metadata.json
+++ b/chrome/browser/flag-metadata.json
@@ -2736,11 +2736,6 @@
     "expiry_milestone": 76
   },
   {
-    "name": "omnibox-wrap-popup-position",
-    "owners": [ "krb", "chrome-omnibox-team@google.com" ],
-    "expiry_milestone": 78
-  },
-  {
     "name": "omnibox-zero-suggestions-on-ntp",
     "owners": [ "chrome-omnibox-team@google.com" ],
     "expiry_milestone": 81
diff --git a/chrome/browser/flag_descriptions.cc b/chrome/browser/flag_descriptions.cc
index 27904649..f3b4261 100644
--- a/chrome/browser/flag_descriptions.cc
+++ b/chrome/browser/flag_descriptions.cc
@@ -2974,10 +2974,6 @@
     "Put each tab switch suggestion in a separate suggestion, immediately "
     "following the original suggestion.";
 
-const char kOmniboxWrapPopupPositionName[] = "Omnibox wrap pop-up position";
-const char kOmniboxWrapPopupPositionDescription[] =
-    "Enable wrapping the Omnibox pop-up position between top and bottom.";
-
 const char kProactiveTabFreezeAndDiscardName[] =
     "Proactive Tab Freeze and Discard";
 const char kProactiveTabFreezeAndDiscardDescription[] =
diff --git a/chrome/browser/flag_descriptions.h b/chrome/browser/flag_descriptions.h
index f3ba0e0..90f242f 100644
--- a/chrome/browser/flag_descriptions.h
+++ b/chrome/browser/flag_descriptions.h
@@ -1743,9 +1743,6 @@
 extern const char kOmniboxTabSwitchSuggestionsDedicatedRowName[];
 extern const char kOmniboxTabSwitchSuggestionsDedicatedRowDescription[];
 
-extern const char kOmniboxWrapPopupPositionName[];
-extern const char kOmniboxWrapPopupPositionDescription[];
-
 extern const char kProactiveTabFreezeAndDiscardName[];
 extern const char kProactiveTabFreezeAndDiscardDescription[];
 
diff --git a/chrome/browser/media/router/discovery/dial/device_description_fetcher_unittest.cc b/chrome/browser/media/router/discovery/dial/device_description_fetcher_unittest.cc
index 38e64212..145a64e 100644
--- a/chrome/browser/media/router/discovery/dial/device_description_fetcher_unittest.cc
+++ b/chrome/browser/media/router/discovery/dial/device_description_fetcher_unittest.cc
@@ -86,12 +86,12 @@
   std::string body("<xml>description</xml>");
   EXPECT_CALL(*this, OnSuccess(DialDeviceDescriptionData(
                          body, GURL("http://127.0.0.1/apps"))));
-  network::ResourceResponseHead head;
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
-  head.headers->AddHeader("Application-URL: http://127.0.0.1/apps");
+  auto head = network::mojom::URLResponseHead::New();
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+  head->headers->AddHeader("Application-URL: http://127.0.0.1/apps");
   network::URLLoaderCompletionStatus status;
   status.decoded_body_length = body.size();
-  loader_factory_.AddResponse(url_, head, body, status);
+  loader_factory_.AddResponse(url_, std::move(head), body, status);
   StartRequest();
 }
 
@@ -99,19 +99,19 @@
   std::string body("<xml>description</xml>");
   EXPECT_CALL(*this, OnSuccess(DialDeviceDescriptionData(
                          body, GURL("http://127.0.0.1/apps"))));
-  network::ResourceResponseHead head;
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
-  head.headers->AddHeader("Application-URL: http://127.0.0.1/apps/");
+  auto head = network::mojom::URLResponseHead::New();
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+  head->headers->AddHeader("Application-URL: http://127.0.0.1/apps/");
   network::URLLoaderCompletionStatus status;
   status.decoded_body_length = body.size();
-  loader_factory_.AddResponse(url_, head, body, status);
+  loader_factory_.AddResponse(url_, std::move(head), body, status);
   StartRequest();
 }
 
 TEST_F(DeviceDescriptionFetcherTest, FetchFailsOnMissingDescription) {
   EXPECT_CALL(*this, OnError(HasSubstr("404")));
   loader_factory_.AddResponse(
-      url_, network::ResourceResponseHead(), "",
+      url_, network::mojom::URLResponseHead::New(), "",
       network::URLLoaderCompletionStatus(net::HTTP_NOT_FOUND));
   StartRequest();
 }
@@ -121,42 +121,42 @@
   EXPECT_CALL(*this, OnError(HasSubstr("Missing or empty Application-URL:")));
   network::URLLoaderCompletionStatus status;
   status.decoded_body_length = body.size();
-  loader_factory_.AddResponse(url_, network::ResourceResponseHead(), body,
-                              status);
+  loader_factory_.AddResponse(url_, network::mojom::URLResponseHead::New(),
+                              body, status);
   StartRequest();
 }
 
 TEST_F(DeviceDescriptionFetcherTest, FetchFailsOnEmptyAppUrl) {
   EXPECT_CALL(*this, OnError(HasSubstr("Missing or empty Application-URL:")));
   std::string body("<xml>description</xml>");
-  network::ResourceResponseHead head;
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
-  head.headers->AddHeader("Application-URL:");
+  auto head = network::mojom::URLResponseHead::New();
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+  head->headers->AddHeader("Application-URL:");
   network::URLLoaderCompletionStatus status;
   status.decoded_body_length = body.size();
-  loader_factory_.AddResponse(url_, head, body, status);
+  loader_factory_.AddResponse(url_, std::move(head), body, status);
   StartRequest();
 }
 
 TEST_F(DeviceDescriptionFetcherTest, FetchFailsOnInvalidAppUrl) {
   EXPECT_CALL(*this, OnError(HasSubstr("Invalid Application-URL:")));
   std::string body("<xml>description</xml>");
-  network::ResourceResponseHead head;
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
-  head.headers->AddHeader("Application-URL: http://www.example.com");
+  auto head = network::mojom::URLResponseHead::New();
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+  head->headers->AddHeader("Application-URL: http://www.example.com");
   network::URLLoaderCompletionStatus status;
   status.decoded_body_length = body.size();
-  loader_factory_.AddResponse(url_, head, body, status);
+  loader_factory_.AddResponse(url_, std::move(head), body, status);
   StartRequest();
 }
 
 TEST_F(DeviceDescriptionFetcherTest, FetchFailsOnEmptyDescription) {
   EXPECT_CALL(*this, OnError(HasSubstr("Missing or empty response")));
-  network::ResourceResponseHead head;
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
-  head.headers->AddHeader("Application-URL: http://127.0.0.1/apps");
+  auto head = network::mojom::URLResponseHead::New();
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+  head->headers->AddHeader("Application-URL: http://127.0.0.1/apps");
 
-  loader_factory_.AddResponse(url_, head, "",
+  loader_factory_.AddResponse(url_, std::move(head), "",
                               network::URLLoaderCompletionStatus());
   StartRequest();
 }
@@ -164,12 +164,12 @@
 TEST_F(DeviceDescriptionFetcherTest, FetchFailsOnBadDescription) {
   EXPECT_CALL(*this, OnError(HasSubstr("Invalid response encoding")));
   std::string body("\xfc\x9c\xbf\x80\xbf\x80");
-  network::ResourceResponseHead head;
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
-  head.headers->AddHeader("Application-URL: http://127.0.0.1/apps");
+  auto head = network::mojom::URLResponseHead::New();
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+  head->headers->AddHeader("Application-URL: http://127.0.0.1/apps");
   network::URLLoaderCompletionStatus status;
   status.decoded_body_length = body.size();
-  loader_factory_.AddResponse(url_, head, body, status);
+  loader_factory_.AddResponse(url_, std::move(head), body, status);
   StartRequest();
 }
 
diff --git a/chrome/browser/media/router/discovery/dial/dial_url_fetcher_unittest.cc b/chrome/browser/media/router/discovery/dial/dial_url_fetcher_unittest.cc
index 2a08b1b..7dc552f 100644
--- a/chrome/browser/media/router/discovery/dial/dial_url_fetcher_unittest.cc
+++ b/chrome/browser/media/router/discovery/dial/dial_url_fetcher_unittest.cc
@@ -59,22 +59,22 @@
   EXPECT_CALL(*this, OnSuccess(body));
   network::URLLoaderCompletionStatus status;
   status.decoded_body_length = body.size();
-  loader_factory_.AddResponse(url_, network::ResourceResponseHead(), body,
-                              status);
+  loader_factory_.AddResponse(url_, network::mojom::URLResponseHead::New(),
+                              body, status);
   StartGetRequest();
 }
 
 TEST_F(DialURLFetcherTest, FetchFailsOnMissingAppInfo) {
   EXPECT_CALL(*this, OnError(404, HasSubstr("404")));
   loader_factory_.AddResponse(
-      url_, network::ResourceResponseHead(), "",
+      url_, network::mojom::URLResponseHead::New(), "",
       network::URLLoaderCompletionStatus(net::HTTP_NOT_FOUND));
   StartGetRequest();
 }
 
 TEST_F(DialURLFetcherTest, FetchFailsOnEmptyAppInfo) {
   EXPECT_CALL(*this, OnError(_, HasSubstr("Missing or empty response")));
-  loader_factory_.AddResponse(url_, network::ResourceResponseHead(), "",
+  loader_factory_.AddResponse(url_, network::mojom::URLResponseHead::New(), "",
                               network::URLLoaderCompletionStatus());
   StartGetRequest();
 }
@@ -84,8 +84,8 @@
   std::string body("\xfc\x9c\xbf\x80\xbf\x80");
   network::URLLoaderCompletionStatus status;
   status.decoded_body_length = body.size();
-  loader_factory_.AddResponse(url_, network::ResourceResponseHead(), body,
-                              status);
+  loader_factory_.AddResponse(url_, network::mojom::URLResponseHead::New(),
+                              body, status);
   StartGetRequest();
 }
 
diff --git a/chrome/browser/media/router/providers/dial/dial_activity_manager_unittest.cc b/chrome/browser/media/router/providers/dial/dial_activity_manager_unittest.cc
index ae15450b..15137d7 100644
--- a/chrome/browser/media/router/providers/dial/dial_activity_manager_unittest.cc
+++ b/chrome/browser/media/router/providers/dial/dial_activity_manager_unittest.cc
@@ -66,14 +66,15 @@
     LaunchApp(activity.route.media_route_id(), base::nullopt);
     LaunchApp(activity.route.media_route_id(), "bar");
 
-    network::ResourceResponseHead response_head;
+    auto response_head = network::mojom::URLResponseHead::New();
     if (app_instance_url) {
-      response_head.headers =
+      response_head->headers =
           base::MakeRefCounted<net::HttpResponseHeaders>("");
-      response_head.headers->AddHeader("LOCATION: " + app_instance_url->spec());
+      response_head->headers->AddHeader("LOCATION: " +
+                                        app_instance_url->spec());
     }
     loader_factory_.AddResponse(activity.launch_info.app_launch_url,
-                                response_head, "",
+                                std::move(response_head), "",
                                 network::URLLoaderCompletionStatus());
     EXPECT_CALL(*this, OnAppLaunchResult(true));
     base::RunLoop().RunUntilIdle();
@@ -165,9 +166,9 @@
                               "foo");
   LaunchApp(activity->route.media_route_id(), base::nullopt);
 
-  network::ResourceResponseHead response_head;
   loader_factory_.AddResponse(
-      activity->launch_info.app_launch_url, response_head, "",
+      activity->launch_info.app_launch_url,
+      network::mojom::URLResponseHead::New(), "",
       network::URLLoaderCompletionStatus(net::HTTP_SERVICE_UNAVAILABLE));
   EXPECT_CALL(*this, OnAppLaunchResult(false));
   base::RunLoop().RunUntilIdle();
@@ -197,8 +198,9 @@
   can_stop = manager_.CanStopApp(activity->route.media_route_id());
   EXPECT_NE(can_stop.second, RouteRequestResult::OK);
 
-  loader_factory_.AddResponse(app_instance_url, network::ResourceResponseHead(),
-                              "", network::URLLoaderCompletionStatus());
+  loader_factory_.AddResponse(app_instance_url,
+                              network::mojom::URLResponseHead::New(), "",
+                              network::URLLoaderCompletionStatus());
   EXPECT_CALL(*this, OnStopAppResult(testing::Eq(base::nullopt),
                                      RouteRequestResult::OK));
   base::RunLoop().RunUntilIdle();
@@ -219,8 +221,9 @@
   manager_.SetExpectedRequest(app_instance_url, "DELETE", base::nullopt);
   StopApp(activity->route.media_route_id());
 
-  loader_factory_.AddResponse(app_instance_url, network::ResourceResponseHead(),
-                              "", network::URLLoaderCompletionStatus());
+  loader_factory_.AddResponse(app_instance_url,
+                              network::mojom::URLResponseHead::New(), "",
+                              network::URLLoaderCompletionStatus());
   EXPECT_CALL(*this, OnStopAppResult(testing::Eq(base::nullopt),
                                      RouteRequestResult::OK));
   base::RunLoop().RunUntilIdle();
@@ -242,7 +245,7 @@
   StopApp(activity->route.media_route_id());
 
   loader_factory_.AddResponse(
-      app_instance_url, network::ResourceResponseHead(), "",
+      app_instance_url, network::mojom::URLResponseHead::New(), "",
       network::URLLoaderCompletionStatus(net::HTTP_SERVICE_UNAVAILABLE));
   EXPECT_CALL(*this, OnStopAppResult(_, Not(RouteRequestResult::OK)));
   base::RunLoop().RunUntilIdle();
diff --git a/chrome/browser/media/router/providers/dial/dial_media_route_provider_unittest.cc b/chrome/browser/media/router/providers/dial/dial_media_route_provider_unittest.cc
index 7420f87..2f32e8e 100644
--- a/chrome/browser/media/router/providers/dial/dial_media_route_provider_unittest.cc
+++ b/chrome/browser/media/router/providers/dial/dial_media_route_provider_unittest.cc
@@ -262,10 +262,10 @@
 
     // Simulate a successful launch response.
     app_instance_url_ = GURL(app_launch_url.spec() + "/run");
-    network::ResourceResponseHead response_head;
-    response_head.headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
-    response_head.headers->AddHeader("LOCATION: " + app_instance_url_.spec());
-    loader_factory_.AddResponse(app_launch_url, response_head, "",
+    auto response_head = network::mojom::URLResponseHead::New();
+    response_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+    response_head->headers->AddHeader("LOCATION: " + app_instance_url_.spec());
+    loader_factory_.AddResponse(app_launch_url, std::move(response_head), "",
                                 network::URLLoaderCompletionStatus());
     std::vector<MediaRoute> routes;
     EXPECT_CALL(mock_router_, OnRoutesUpdated(_, Not(IsEmpty()), _, IsEmpty()))
@@ -283,7 +283,7 @@
     activity_manager_->SetExpectedRequest(app_instance_url_, "DELETE",
                                           base::nullopt);
     loader_factory_.AddResponse(app_instance_url_,
-                                network::ResourceResponseHead(), "",
+                                network::mojom::URLResponseHead::New(), "",
                                 network::URLLoaderCompletionStatus());
     EXPECT_CALL(*this, OnTerminateRoute(_, RouteRequestResult::OK));
     provider_->TerminateRoute(
@@ -323,7 +323,7 @@
     activity_manager_->SetExpectedRequest(app_instance_url_, "DELETE",
                                           base::nullopt);
     loader_factory_.AddResponse(app_instance_url_,
-                                network::ResourceResponseHead(), "",
+                                network::mojom::URLResponseHead::New(), "",
                                 network::URLLoaderCompletionStatus());
 
     provider_->SendRouteMessage(route_id, kStopSessionMessage);
@@ -360,7 +360,7 @@
     activity_manager_->SetExpectedRequest(app_instance_url_, "DELETE",
                                           base::nullopt);
     loader_factory_.AddResponse(
-        app_instance_url_, network::ResourceResponseHead(), "",
+        app_instance_url_, network::mojom::URLResponseHead::New(), "",
         network::URLLoaderCompletionStatus(net::HTTP_SERVICE_UNAVAILABLE));
     EXPECT_CALL(*this,
                 OnTerminateRoute(_, testing::Ne(RouteRequestResult::OK)));
diff --git a/chrome/browser/media/webrtc/webrtc_event_log_uploader_impl_unittest.cc b/chrome/browser/media/webrtc/webrtc_event_log_uploader_impl_unittest.cc
index 4feb66c..853cc08 100644
--- a/chrome/browser/media/webrtc/webrtc_event_log_uploader_impl_unittest.cc
+++ b/chrome/browser/media/webrtc/webrtc_event_log_uploader_impl_unittest.cc
@@ -122,7 +122,7 @@
     const std::string kResponseId = "ec1ed029734b8f7e";  // Arbitrary.
     test_url_loader_factory_.AddResponse(
         GURL(WebRtcEventLogUploaderImpl::kUploadURL),
-        network::CreateResourceResponseHead(http_code), kResponseId,
+        network::CreateURLResponseHead(http_code), kResponseId,
         network::URLLoaderCompletionStatus(net_error));
   }
 
diff --git a/chrome/browser/memory/enterprise_memory_limit_evaluator.cc b/chrome/browser/memory/enterprise_memory_limit_evaluator.cc
index 44b8c8e..595de3d 100644
--- a/chrome/browser/memory/enterprise_memory_limit_evaluator.cc
+++ b/chrome/browser/memory/enterprise_memory_limit_evaluator.cc
@@ -85,6 +85,11 @@
   resident_set_limit_mb_ = resident_set_limit_mb;
 }
 
+bool EnterpriseMemoryLimitEvaluator::IsRunning() const {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  return observer_ != nullptr;
+}
+
 EnterpriseMemoryLimitEvaluator::GraphObserver::GraphObserver(
     base::RepeatingCallback<void(uint64_t)> on_sample_callback,
     scoped_refptr<base::SequencedTaskRunner> task_runner)
diff --git a/chrome/browser/memory/enterprise_memory_limit_evaluator.h b/chrome/browser/memory/enterprise_memory_limit_evaluator.h
index 59f3069..1f327d5 100644
--- a/chrome/browser/memory/enterprise_memory_limit_evaluator.h
+++ b/chrome/browser/memory/enterprise_memory_limit_evaluator.h
@@ -7,6 +7,7 @@
 
 #include "base/callback.h"
 #include "base/memory/weak_ptr.h"
+#include "base/sequence_checker.h"
 #include "base/threading/sequenced_task_runner_handle.h"
 #include "base/util/memory_pressure/memory_pressure_voter.h"
 #include "chrome/browser/performance_manager/public/graph/graph.h"
@@ -32,13 +33,15 @@
   void Start();
   void Stop();
 
-  std::unique_ptr<EnterpriseMemoryLimitEvaluator::GraphObserver>
-  StartForTesting();
+  std::unique_ptr<GraphObserver> StartForTesting();
   void StopForTesting();
 
   // Sets the limit against which the total resident set will be compared.
   void SetResidentSetLimitMb(uint64_t resident_set_limit_mb);
 
+  // Indicates if this evaluator is currently running.
+  bool IsRunning() const;
+
  private:
   // Called on the sequence that owns this object every time a new total RSS
   // sample is available.
diff --git a/chrome/browser/memory/enterprise_memory_limit_pref_observer.cc b/chrome/browser/memory/enterprise_memory_limit_pref_observer.cc
new file mode 100644
index 0000000..0fe5ed9
--- /dev/null
+++ b/chrome/browser/memory/enterprise_memory_limit_pref_observer.cc
@@ -0,0 +1,64 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/memory/enterprise_memory_limit_pref_observer.h"
+
+#include "base/bind.h"
+#include "base/memory/memory_pressure_monitor.h"
+#include "base/util/memory_pressure/multi_source_memory_pressure_monitor.h"
+#include "chrome/common/pref_names.h"
+
+namespace memory {
+
+namespace {
+const int kMinimalResidentSetLimitMb = 2048;
+}  // namespace
+
+EnterpriseMemoryLimitPrefObserver::EnterpriseMemoryLimitPrefObserver(
+    PrefService* pref_service)
+    : pref_service_(pref_service) {
+  DCHECK(pref_service_);
+  DCHECK(base::MemoryPressureMonitor::Get());
+  evaluator_ = std::make_unique<EnterpriseMemoryLimitEvaluator>(
+      static_cast<util::MultiSourceMemoryPressureMonitor*>(
+          base::MemoryPressureMonitor::Get())
+          ->CreateVoter());
+
+  pref_change_registrar_.Init(pref_service_);
+  pref_change_registrar_.Add(
+      prefs::kTotalMemoryLimitMb,
+      base::BindRepeating(&EnterpriseMemoryLimitPrefObserver::GetPref,
+                          base::Unretained(this)));
+  GetPref();
+}
+
+EnterpriseMemoryLimitPrefObserver::~EnterpriseMemoryLimitPrefObserver() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  if (evaluator_->IsRunning())
+    evaluator_->Stop();
+}
+
+// static
+void EnterpriseMemoryLimitPrefObserver::RegisterPrefs(
+    PrefRegistrySimple* registry) {
+  registry->RegisterIntegerPref(prefs::kTotalMemoryLimitMb,
+                                kMinimalResidentSetLimitMb);
+}
+
+void EnterpriseMemoryLimitPrefObserver::GetPref() {
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
+  const PrefService::Preference* pref =
+      pref_service_->FindPreference(prefs::kTotalMemoryLimitMb);
+
+  if (pref->IsManaged()) {
+    if (!evaluator_->IsRunning())
+      evaluator_->Start();
+    evaluator_->SetResidentSetLimitMb(
+        std::max(pref->GetValue()->GetInt(), kMinimalResidentSetLimitMb));
+  } else if (evaluator_->IsRunning()) {
+    evaluator_->Stop();
+  }
+}
+
+}  // namespace memory
diff --git a/chrome/browser/memory/enterprise_memory_limit_pref_observer.h b/chrome/browser/memory/enterprise_memory_limit_pref_observer.h
new file mode 100644
index 0000000..a5cfecb
--- /dev/null
+++ b/chrome/browser/memory/enterprise_memory_limit_pref_observer.h
@@ -0,0 +1,49 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_MEMORY_ENTERPRISE_MEMORY_LIMIT_PREF_OBSERVER_H_
+#define CHROME_BROWSER_MEMORY_ENTERPRISE_MEMORY_LIMIT_PREF_OBSERVER_H_
+
+#include "base/sequence_checker.h"
+#include "chrome/browser/memory/enterprise_memory_limit_evaluator.h"
+#include "components/prefs/pref_change_registrar.h"
+#include "components/prefs/pref_registry_simple.h"
+#include "components/prefs/pref_service.h"
+
+namespace memory {
+
+// Tracks changes to the TotalMemoryLimitMb policy and starts/stops/updates
+// the limit of its EnterpriseMemoryLimitEvaluator accordingly.
+class EnterpriseMemoryLimitPrefObserver {
+ public:
+  explicit EnterpriseMemoryLimitPrefObserver(PrefService* pref_service);
+  ~EnterpriseMemoryLimitPrefObserver();
+
+  // Registers the TotalMemoryLimitMb pref with the provided PrefRegistry.
+  // Should only be called by RegisterLocalState() in
+  // chrome/browser/prefs/browser_prefs.cc.
+  static void RegisterPrefs(PrefRegistrySimple* registry);
+
+ private:
+  // Gets the value of the TotalMemoryLimitMb preference and updates the
+  // evaluator accordingly.
+  void GetPref();
+
+  // PrefService from which we get the preference upon notification that the
+  // preference has changed.
+  PrefService* pref_service_;
+
+  // Registrar which notifies us of changes to the preference.
+  PrefChangeRegistrar pref_change_registrar_;
+
+  // Evaluator which sends its votes to the MultiSourceMemoryPressureMonitor.
+  // Should only be running when the preference is enabled.
+  std::unique_ptr<EnterpriseMemoryLimitEvaluator> evaluator_;
+
+  SEQUENCE_CHECKER(sequence_checker_);
+};
+
+}  // namespace memory
+
+#endif  // CHROME_BROWSER_MEMORY_ENTERPRISE_MEMORY_LIMIT_PREF_OBSERVER_H_
diff --git a/chrome/browser/metrics/metrics_service_browsertest.cc b/chrome/browser/metrics/metrics_service_browsertest.cc
index 6e52e73f..dc666d98 100644
--- a/chrome/browser/metrics/metrics_service_browsertest.cc
+++ b/chrome/browser/metrics/metrics_service_browsertest.cc
@@ -186,6 +186,8 @@
   EXPECT_EQ(1, prefs->GetInteger(metrics::prefs::kStabilityRendererCrashCount));
 
 #if defined(OS_WIN)
+  // Consult Stability Team before changing this test as it's recorded to
+  // histograms and used for stability measurement.
   histogram_tester.ExpectUniqueSample(
       "CrashExitCodes.Renderer",
       std::abs(static_cast<int32_t>(STATUS_ACCESS_VIOLATION)), 1);
@@ -230,6 +232,8 @@
   EXPECT_EQ(1, prefs->GetInteger(metrics::prefs::kStabilityRendererCrashCount));
 
 #if defined(OS_WIN)
+  // Consult Stability Team before changing this test as it's recorded to
+  // histograms and used for stability measurement.
   histogram_tester.ExpectUniqueSample(
       "CrashExitCodes.Renderer",
       std::abs(static_cast<int32_t>(STATUS_BREAKPOINT)), 1);
diff --git a/chrome/browser/net/chrome_network_service_browsertest.cc b/chrome/browser/net/chrome_network_service_browsertest.cc
index b98f2d1..917948a 100644
--- a/chrome/browser/net/chrome_network_service_browsertest.cc
+++ b/chrome/browser/net/chrome_network_service_browsertest.cc
@@ -19,10 +19,6 @@
 #include "services/network/public/cpp/features.h"
 #include "services/network/public/mojom/network_service.mojom.h"
 
-#if defined(OS_MACOSX)
-#include "base/mac/mac_util.h"
-#endif
-
 namespace content {
 namespace {
 
@@ -59,6 +55,14 @@
   run_loop.Run();
 }
 
+void FlushCookies(
+    const mojo::Remote<network::mojom::CookieManager>& cookie_manager) {
+  base::RunLoop run_loop;
+  cookie_manager->FlushCookieStore(
+      base::BindLambdaForTesting([&]() { run_loop.Quit(); }));
+  run_loop.Run();
+}
+
 // See |NetworkServiceBrowserTest| for content's version of tests.
 class ChromeNetworkServiceBrowserTest : public InProcessBrowserTest {
  public:
@@ -96,23 +100,11 @@
   ASSERT_EQ(1u, cookies.size());
   EXPECT_EQ(kCookieName, cookies[0].Name());
   EXPECT_EQ(kCookieValue, cookies[0].Value());
+
+  FlushCookies(cookie_manager);
 }
 
-#if defined(OS_WIN)
-// The cookies.size() ASSERT is failing flakily on the Win7 bots.
-// See https://crbug.com/868667
-#define MAYBE_EncryptedCookies DISABLED_EncryptedCookies
-#else
-#define MAYBE_EncryptedCookies EncryptedCookies
-#endif
-
-IN_PROC_BROWSER_TEST_F(ChromeNetworkServiceBrowserTest,
-                       MAYBE_EncryptedCookies) {
-#if defined(OS_MACOSX)
-  // TODO(https://crbug.com/868667): Fix and reenable test.
-  if (base::mac::IsOS10_11())
-    return;
-#endif
+IN_PROC_BROWSER_TEST_F(ChromeNetworkServiceBrowserTest, EncryptedCookies) {
   net::CookieCryptoDelegate* crypto_delegate =
       cookie_config::GetCookieCryptoDelegate();
   std::string ciphertext;
diff --git a/chrome/browser/net/file_downloader_unittest.cc b/chrome/browser/net/file_downloader_unittest.cc
index 16ebf0e3..78d3bade 100644
--- a/chrome/browser/net/file_downloader_unittest.cc
+++ b/chrome/browser/net/file_downloader_unittest.cc
@@ -52,7 +52,7 @@
 
   void SetFailedResponse() {
     test_url_loader_factory_.AddResponse(
-        GURL(kURL), network::ResourceResponseHead(), std::string(),
+        GURL(kURL), network::mojom::URLResponseHead::New(), std::string(),
         network::URLLoaderCompletionStatus(net::HTTP_NOT_FOUND));
   }
 
diff --git a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
index 580eb81..0f96fb6 100644
--- a/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
+++ b/chrome/browser/page_load_metrics/observers/ad_metrics/ads_page_load_metrics_observer_browsertest.cc
@@ -31,6 +31,8 @@
 #include "components/subresource_filter/core/common/test_ruleset_utils.h"
 #include "components/subresource_filter/core/mojom/subresource_filter.mojom.h"
 #include "components/ukm/test_ukm_recorder.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/common/content_features.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test.h"
 #include "content/public/test/browser_test_utils.h"
@@ -91,9 +93,7 @@
     : public subresource_filter::SubresourceFilterBrowserTest {
  public:
   AdsPageLoadMetricsObserverBrowserTest()
-      : subresource_filter::SubresourceFilterBrowserTest() {
-    scoped_feature_list_.InitAndEnableFeature(subresource_filter::kAdTagging);
-  }
+      : subresource_filter::SubresourceFilterBrowserTest() {}
   ~AdsPageLoadMetricsObserverBrowserTest() override {}
 
   std::unique_ptr<page_load_metrics::PageLoadMetricsTestWaiter>
@@ -104,6 +104,20 @@
         web_contents);
   }
 
+  void SetUp() override {
+    std::vector<base::Feature> enabled = {subresource_filter::kAdTagging,
+                                          features::kSitePerProcess};
+    std::vector<base::Feature> disabled = {};
+
+    if (use_process_priority_) {
+      enabled.push_back(features::kUseFramePriorityInRenderProcessHost);
+    } else {
+      disabled.push_back(features::kUseFramePriorityInRenderProcessHost);
+    }
+    scoped_feature_list_.InitWithFeatures(enabled, disabled);
+    subresource_filter::SubresourceFilterBrowserTest::SetUp();
+  }
+
   void SetUpOnMainThread() override {
     SubresourceFilterBrowserTest::SetUpOnMainThread();
     SetRulesetWithRules(
@@ -113,6 +127,9 @@
              "expensive_animation_frame.html*")});
   }
 
+ protected:
+  bool use_process_priority_ = false;
+
  private:
   base::test::ScopedFeatureList scoped_feature_list_;
 
@@ -1293,3 +1310,156 @@
   histogram_tester.ExpectTotalCount(
       "PageLoad.Clients.Ads.Bytes.AdFrames.Aggregate.Total", 0);
 }
+
+IN_PROC_BROWSER_TEST_F(
+    AdsPageLoadMetricsObserverBrowserTest,
+    RenderProcessHostNotBackgroundedWhenFramePriorityDisabled) {
+  // Used for assignment during testing.
+  auto frame1_pred = base::BindRepeating(&content::FrameMatchesName, "iframe1");
+  auto frame2_pred = base::BindRepeating(&content::FrameMatchesName, "iframe2");
+
+  // Navigate to a page with an iframe.  Make sure the two frames share a
+  // process and that process is not low priority.
+  ui_test_utils::NavigateToURL(
+      browser(), embedded_test_server()->GetURL("/two_iframes_blank.html"));
+  content::RenderFrameHost* main_frame = web_contents()->GetMainFrame();
+  content::RenderFrameHost* frame1 =
+      content::FrameMatchingPredicate(web_contents(), frame1_pred);
+  content::RenderFrameHost* frame2 =
+      content::FrameMatchingPredicate(web_contents(), frame2_pred);
+  EXPECT_EQ(main_frame->GetProcess(), frame1->GetProcess());
+  EXPECT_EQ(main_frame->GetProcess(), frame2->GetProcess());
+  EXPECT_FALSE(main_frame->GetProcess()->IsProcessBackgrounded());
+
+  // Navigate iframe1 to a cross-origin non-ad frame.  It should be on a
+  // different process, but still not be low priority.
+  NavigateIframeToURL(
+      web_contents(), "iframe1",
+      embedded_test_server()->GetURL("a.com", "/iframe_blank.html"));
+  frame1 = content::FrameMatchingPredicate(web_contents(), frame1_pred);
+  EXPECT_NE(main_frame->GetProcess(), frame1->GetProcess());
+  EXPECT_FALSE(main_frame->GetProcess()->IsProcessBackgrounded());
+  EXPECT_FALSE(frame1->GetProcess()->IsProcessBackgrounded());
+
+  // Navigate iframe1 to an ad on its current domain.  It should have the same
+  // process host but because the feature is turned off, not be low priority.
+  content::DOMMessageQueue message_queue1(web_contents());
+  NavigateIframeToURL(
+      web_contents(), "iframe1",
+      embedded_test_server()->GetURL(
+          "a.com", "/ads_observer/expensive_animation_frame.html?delay=0"));
+  WaitForRAF(&message_queue1);
+  EXPECT_EQ(frame1->GetProcess(),
+            content::FrameMatchingPredicate(web_contents(), frame1_pred)
+                ->GetProcess());
+  EXPECT_FALSE(main_frame->GetProcess()->IsProcessBackgrounded());
+  EXPECT_FALSE(frame1->GetProcess()->IsProcessBackgrounded());
+}
+
+class AdsPageLoadMetricsObserverWithBackgroundingBrowserTest
+    : public AdsPageLoadMetricsObserverBrowserTest {
+ public:
+  AdsPageLoadMetricsObserverWithBackgroundingBrowserTest()
+      : AdsPageLoadMetricsObserverBrowserTest() {
+    use_process_priority_ = true;
+  }
+  ~AdsPageLoadMetricsObserverWithBackgroundingBrowserTest() override {}
+};
+
+IN_PROC_BROWSER_TEST_F(AdsPageLoadMetricsObserverWithBackgroundingBrowserTest,
+                       RenderProcessHostBackgroundedForAd) {
+  // Used for assignment during testing.
+  auto frame1_pred = base::BindRepeating(&content::FrameMatchesName, "iframe1");
+  auto frame2_pred = base::BindRepeating(&content::FrameMatchesName, "iframe2");
+
+  // Navigate to a page with an iframe.  Make sure the two frames share a
+  // process and that process is not low priority.
+  ui_test_utils::NavigateToURL(
+      browser(), embedded_test_server()->GetURL("/two_iframes_blank.html"));
+  content::RenderFrameHost* main_frame = web_contents()->GetMainFrame();
+  content::RenderFrameHost* frame1 =
+      content::FrameMatchingPredicate(web_contents(), frame1_pred);
+  content::RenderFrameHost* frame2 =
+      content::FrameMatchingPredicate(web_contents(), frame2_pred);
+  EXPECT_EQ(main_frame->GetProcess(), frame1->GetProcess());
+  EXPECT_EQ(main_frame->GetProcess(), frame2->GetProcess());
+  EXPECT_FALSE(main_frame->GetProcess()->IsProcessBackgrounded());
+
+  // Navigate iframe1 to a cross-origin non-ad frame.  It should be on a
+  // different process, but still not be low priority.
+  NavigateIframeToURL(
+      web_contents(), "iframe1",
+      embedded_test_server()->GetURL("a.com", "/iframe_blank.html"));
+  frame1 = content::FrameMatchingPredicate(web_contents(), frame1_pred);
+  EXPECT_NE(main_frame->GetProcess(), frame1->GetProcess());
+  EXPECT_FALSE(main_frame->GetProcess()->IsProcessBackgrounded());
+  EXPECT_FALSE(frame1->GetProcess()->IsProcessBackgrounded());
+
+  // Navigate iframe1 to an ad on its current domain.  It should have the
+  // same process host but now be low priority.
+  content::DOMMessageQueue message_queue1(web_contents());
+  NavigateIframeToURL(
+      web_contents(), "iframe1",
+      embedded_test_server()->GetURL(
+          "a.com", "/ads_observer/expensive_animation_frame.html?delay=0"));
+  WaitForRAF(&message_queue1);
+  EXPECT_EQ(frame1->GetProcess(),
+            content::FrameMatchingPredicate(web_contents(), frame1_pred)
+                ->GetProcess());
+  EXPECT_FALSE(main_frame->GetProcess()->IsProcessBackgrounded());
+  EXPECT_TRUE(frame1->GetProcess()->IsProcessBackgrounded());
+
+  // Navigate the iframe2 to a non-ad on the same domain as iframe1.  Make sure
+  // that they get assigned the same process and that it's not low priority.
+  NavigateIframeToURL(
+      web_contents(), "iframe2",
+      embedded_test_server()->GetURL("a.com", "/iframe_blank.html"));
+  frame2 = content::FrameMatchingPredicate(web_contents(), frame2_pred);
+  EXPECT_EQ(frame1->GetProcess(), frame2->GetProcess());
+  EXPECT_FALSE(main_frame->GetProcess()->IsProcessBackgrounded());
+  EXPECT_FALSE(frame1->GetProcess()->IsProcessBackgrounded());
+
+  // Delete iframe2, make sure that iframe1 is now low priority, as it now only
+  // has ads assigned to it.
+  EXPECT_TRUE(content::ExecuteScriptWithoutUserGesture(
+      web_contents(),
+      "var frame = document.getElementById('iframe2'); "
+      "frame.parentNode.removeChild(frame);"));
+  EXPECT_TRUE(frame1->GetProcess()->IsProcessBackgrounded());
+
+  // Navigate the subframe to a non-ad on its current domain.  Even though this
+  // is a non-ad, the frame is still identified as an ad because it was
+  // previously identified as an ad by SubresourceFilterThrottle.
+  NavigateIframeToURL(
+      web_contents(), "iframe1",
+      embedded_test_server()->GetURL("a.com", "/iframe_blank.html"));
+  EXPECT_EQ(frame1->GetProcess(),
+            content::FrameMatchingPredicate(web_contents(), frame1_pred)
+                ->GetProcess());
+  EXPECT_FALSE(main_frame->GetProcess()->IsProcessBackgrounded());
+  EXPECT_TRUE(frame1->GetProcess()->IsProcessBackgrounded());
+
+  // Navigate the subframe to an ad on the original domain.  It should now have
+  // the same process as the main frame, but not be low priority because it
+  // shares a process with a non-ad frame (the main frame).
+  content::DOMMessageQueue message_queue2(web_contents());
+  NavigateIframeToURL(
+      web_contents(), "iframe1",
+      embedded_test_server()->GetURL(
+          "/ads_observer/expensive_animation_frame.html?delay=0"));
+  WaitForRAF(&message_queue2);
+  frame1 = content::FrameMatchingPredicate(web_contents(), frame1_pred);
+  EXPECT_EQ(main_frame->GetProcess(), frame1->GetProcess());
+  EXPECT_FALSE(frame1->GetProcess()->IsProcessBackgrounded());
+
+  // Navigate the subframe to a non-ad on a different domain.  Even though this
+  // is a non-ad, the frame is still identified as an ad because it was
+  // previously identified as an ad by SubresourceFilterThrottle.
+  NavigateIframeToURL(
+      web_contents(), "iframe1",
+      embedded_test_server()->GetURL("b.com", "/iframe_blank.html"));
+  frame1 = content::FrameMatchingPredicate(web_contents(), frame1_pred);
+  EXPECT_NE(main_frame->GetProcess(), frame1->GetProcess());
+  EXPECT_FALSE(main_frame->GetProcess()->IsProcessBackgrounded());
+  EXPECT_TRUE(frame1->GetProcess()->IsProcessBackgrounded());
+}
diff --git a/chrome/browser/payments/ssl_validity_checker.cc b/chrome/browser/payments/ssl_validity_checker.cc
index c71e8f9..50ee866 100644
--- a/chrome/browser/payments/ssl_validity_checker.cc
+++ b/chrome/browser/payments/ssl_validity_checker.cc
@@ -48,8 +48,8 @@
     case security_state::NONE:
       level = "NONE";
       break;
-    case security_state::HTTP_SHOW_WARNING:
-      level = "HTTP_SHOW_WARNING";
+    case security_state::WARNING:
+      level = "WARNING";
       break;
     case security_state::DANGEROUS:
       level = "DANGEROUS";
diff --git a/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc b/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc
index f6fcbf3..087f8c5 100644
--- a/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc
+++ b/chrome/browser/policy/cloud/cloud_policy_manager_browsertest.cc
@@ -76,7 +76,7 @@
                             network::TestURLLoaderFactory* factory) {
   network::URLLoaderCompletionStatus status;
   factory->AddResponse(
-      request.url, network::ResourceResponseHead(), std::string(),
+      request.url, network::mojom::URLResponseHead::New(), std::string(),
       network::URLLoaderCompletionStatus(net::ERR_NETWORK_CHANGED));
 }
 
@@ -131,11 +131,10 @@
 
   status.decoded_body_length = content.size();
 
-  network::ResourceResponseHead head =
-      network::CreateResourceResponseHead(net::HTTP_OK);
-  head.mime_type = "application/protobuf";
+  auto head = network::CreateURLResponseHead(net::HTTP_OK);
+  head->mime_type = "application/protobuf";
 
-  factory->AddResponse(request.url, head, content, status);
+  factory->AddResponse(request.url, std::move(head), content, status);
 }
 
 }  // namespace
@@ -277,9 +276,9 @@
   test_url_loader_factory_->SetInterceptor(
       base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
         network::URLLoaderCompletionStatus status(net::ERR_NETWORK_CHANGED);
-        test_url_loader_factory_->AddResponse(request.url,
-                                              network::ResourceResponseHead(),
-                                              std::string(), status);
+        test_url_loader_factory_->AddResponse(
+            request.url, network::mojom::URLResponseHead::New(), std::string(),
+            status);
         ++count;
       }));
 
@@ -305,9 +304,9 @@
         if (!gave_error) {
           gave_error = true;
           network::URLLoaderCompletionStatus status(net::ERR_NETWORK_CHANGED);
-          test_url_loader_factory_->AddResponse(request.url,
-                                                network::ResourceResponseHead(),
-                                                std::string(), status);
+          test_url_loader_factory_->AddResponse(
+              request.url, network::mojom::URLResponseHead::New(),
+              std::string(), status);
           return;
         }
 
diff --git a/chrome/browser/policy/configuration_policy_handler_list_factory.cc b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
index 2af1911..31848eb6 100644
--- a/chrome/browser/policy/configuration_policy_handler_list_factory.cc
+++ b/chrome/browser/policy/configuration_policy_handler_list_factory.cc
@@ -1163,6 +1163,9 @@
   { key::kPasswordLeakDetectionEnabled,
     password_manager::prefs::kPasswordLeakDetectionEnabled,
     base::Value::Type::BOOLEAN },
+  { key::kTotalMemoryLimitMb,
+    prefs::kTotalMemoryLimitMb,
+    base::Value::Type::INTEGER }
 };
 // clang-format on
 
diff --git a/chrome/browser/policy/profile_policy_connector.cc b/chrome/browser/policy/profile_policy_connector.cc
index 288f7efd..98a1121 100644
--- a/chrome/browser/policy/profile_policy_connector.cc
+++ b/chrome/browser/policy/profile_policy_connector.cc
@@ -133,10 +133,12 @@
   DCHECK_EQ(nullptr, user);
 #endif
 
-  if (connector->GetPlatformProvider()) {
-    wrapped_platform_policy_provider_.reset(
-        new SchemaRegistryTrackingPolicyProvider(
-            connector->GetPlatformProvider()));
+  ConfigurationPolicyProvider* platform_provider =
+      GetPlatformProvider(connector);
+  if (platform_provider) {
+    wrapped_platform_policy_provider_ =
+        std::make_unique<SchemaRegistryTrackingPolicyProvider>(
+            platform_provider);
     wrapped_platform_policy_provider_->Init(schema_registry);
     policy_providers_.push_back(wrapped_platform_policy_provider_.get());
   }
@@ -155,7 +157,7 @@
     // Skip the platform provider since it was already handled above.  The
     // platform provider should be first in the list so that it always takes
     // precedence.
-    if (provider == connector->GetPlatformProvider()) {
+    if (provider == platform_provider) {
       continue;
     } else {
       // TODO(zmin): In the future, we may want to have special handling for
@@ -233,6 +235,11 @@
   is_managed_override_.reset(new bool(is_managed));
 }
 
+void ProfilePolicyConnector::SetPlatformPolicyProviderForTesting(
+    ConfigurationPolicyProvider* platform_policy_provider_for_testing) {
+  platform_policy_provider_for_testing_ = platform_policy_provider_for_testing;
+}
+
 void ProfilePolicyConnector::Shutdown() {
 #if defined(OS_CHROMEOS)
   if (is_primary_user_)
@@ -291,6 +298,13 @@
   return nullptr;
 }
 
+ConfigurationPolicyProvider* ProfilePolicyConnector::GetPlatformProvider(
+    policy::ChromeBrowserPolicyConnector* browser_policy_connector) {
+  if (platform_policy_provider_for_testing_)
+    return platform_policy_provider_for_testing_;
+  return browser_policy_connector->GetPlatformProvider();
+}
+
 #if defined(OS_CHROMEOS)
 std::unique_ptr<PolicyService>
 ProfilePolicyConnector::CreatePolicyServiceWithInitializationThrottled(
diff --git a/chrome/browser/policy/profile_policy_connector.h b/chrome/browser/policy/profile_policy_connector.h
index 4c5ec61f..78c0bfc 100644
--- a/chrome/browser/policy/profile_policy_connector.h
+++ b/chrome/browser/policy/profile_policy_connector.h
@@ -54,6 +54,8 @@
 
   void InitForTesting(std::unique_ptr<PolicyService> service);
   void OverrideIsManagedForTesting(bool is_managed);
+  void SetPlatformPolicyProviderForTesting(
+      ConfigurationPolicyProvider* platform_policy_provider_for_testing);
 
   void Shutdown();
 
@@ -80,6 +82,12 @@
   const ConfigurationPolicyProvider* DeterminePolicyProviderForPolicy(
       const char* policy_key) const;
 
+  // Returns the platform policy provider, which will be used as the highest
+  // priority policy provider in PolicyService created by this
+  // ProfilePolicyConnector.
+  ConfigurationPolicyProvider* GetPlatformProvider(
+      policy::ChromeBrowserPolicyConnector* browser_policy_connector);
+
 #if defined(OS_CHROMEOS)
   // On Chrome OS, primary Profile user policies are forwarded to the
   // device-global PolicyService[1] using a ProxyPolicyProvider.
@@ -132,6 +140,10 @@
   const ConfigurationPolicyProvider* configuration_policy_provider_ = nullptr;
   const CloudPolicyStore* policy_store_ = nullptr;
 
+  // If this is not nullptr, this provider will be used as (highest priority)
+  // platform policy provider.
+  ConfigurationPolicyProvider* platform_policy_provider_for_testing_ = nullptr;
+
   // |policy_providers_| contains a list of the policy providers available for
   // the PolicyService of this connector, in decreasing order of priority.
   //
diff --git a/chrome/browser/policy/profile_policy_connector_unittest.cc b/chrome/browser/policy/profile_policy_connector_unittest.cc
index ae61c3d..70750bb1 100644
--- a/chrome/browser/policy/profile_policy_connector_unittest.cc
+++ b/chrome/browser/policy/profile_policy_connector_unittest.cc
@@ -39,6 +39,53 @@
 using testing::_;
 
 namespace policy {
+namespace {
+
+// Waits for a PolicyService to notify its observers that initialization of a
+// PolicyDomain has finished.
+class PolicyServiceInitializedWaiter : PolicyService::Observer {
+ public:
+  // Instantiates a PolicyServiceInitializedWaiter which will wait for
+  // |policy_service| to signal that |policy_domain| has completed
+  // initialization. |policy_service| must outlive this object.
+  PolicyServiceInitializedWaiter(PolicyService* policy_service,
+                                 PolicyDomain policy_domain)
+      : policy_service_(policy_service), policy_domain_(policy_domain) {
+    policy_service_->AddObserver(policy_domain_, this);
+  }
+
+  ~PolicyServiceInitializedWaiter() override {
+    policy_service_->RemoveObserver(policy_domain_, this);
+  }
+
+  // Waits for the PolicyService to signal that the PolicyDomain has completed
+  // initialization. If initialization of the PolicyDomain is already complete
+  // at the time Wait() is called, returns immediately.
+  void Wait() {
+    if (policy_service_->IsInitializationComplete(policy_domain_))
+      return;
+    run_loop_.Run();
+  }
+
+  // PolicyService::Observer:
+  void OnPolicyUpdated(const PolicyNamespace& ns,
+                       const PolicyMap& previous,
+                       const PolicyMap& current) override {}
+
+  // PolicyService::Observer:
+  void OnPolicyServiceInitialized(PolicyDomain domain) override {
+    run_loop_.Quit();
+  }
+
+ private:
+  PolicyService* policy_service_;
+  PolicyDomain policy_domain_;
+  base::RunLoop run_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(PolicyServiceInitializedWaiter);
+};
+
+}  // namespace
 
 class ProfilePolicyConnectorTest : public testing::Test {
  protected:
@@ -46,17 +93,11 @@
   ~ProfilePolicyConnectorTest() override {}
 
   void SetUp() override {
-    // This must be set up before the TestingBrowserProcess is created.
-    BrowserPolicyConnector::SetPolicyProviderForTesting(&mock_provider_);
-
-    EXPECT_CALL(mock_provider_, IsInitializationComplete(_))
-        .WillRepeatedly(Return(true));
-
     cloud_policy_store_.NotifyStoreLoaded();
     const auto task_runner = task_environment_.GetMainThreadTaskRunner();
-    cloud_policy_manager_.reset(new CloudPolicyManager(
+    cloud_policy_manager_ = std::make_unique<CloudPolicyManager>(
         std::string(), std::string(), &cloud_policy_store_, task_runner,
-        network::TestNetworkConnectionTracker::CreateGetter()));
+        network::TestNetworkConnectionTracker::CreateGetter());
     cloud_policy_manager_->Init(&schema_registry_);
   }
 
@@ -75,7 +116,6 @@
   // Needs to be the first member.
   base::test::TaskEnvironment task_environment_;
   SchemaRegistry schema_registry_;
-  MockConfigurationPolicyProvider mock_provider_;
   MockCloudPolicyStore cloud_policy_store_;
   std::unique_ptr<CloudPolicyManager> cloud_policy_manager_;
 
@@ -91,7 +131,8 @@
                  g_browser_process->browser_policy_connector(), false);
   EXPECT_FALSE(connector.IsManaged());
 
-  cloud_policy_store_.policy_.reset(new enterprise_management::PolicyData());
+  cloud_policy_store_.policy_ =
+      std::make_unique<enterprise_management::PolicyData>();
   cloud_policy_store_.policy_->set_username("test@testdomain.com");
   cloud_policy_store_.policy_->set_state(
       enterprise_management::PolicyData::ACTIVE);
@@ -112,7 +153,8 @@
   connector.Init(user.get(), &schema_registry_, cloud_policy_manager_.get(),
                  &cloud_policy_store_,
                  g_browser_process->browser_policy_connector(), false);
-  cloud_policy_store_.policy_.reset(new enterprise_management::PolicyData());
+  cloud_policy_store_.policy_ =
+      std::make_unique<enterprise_management::PolicyData>();
   cloud_policy_store_.policy_->set_state(
       enterprise_management::PolicyData::ACTIVE);
   EXPECT_TRUE(connector.IsManaged());
@@ -125,10 +167,67 @@
   // Cleanup.
   connector.Shutdown();
 }
+
+TEST_F(ProfilePolicyConnectorTest, PrimaryUserPoliciesProxied) {
+  auto user_manager_unique_ptr =
+      std::make_unique<chromeos::FakeChromeUserManager>();
+  chromeos::FakeChromeUserManager* user_manager = user_manager_unique_ptr.get();
+  user_manager::ScopedUserManager scoped_user_manager_enabler(
+      std::move(user_manager_unique_ptr));
+
+  cloud_policy_store_.policy_ =
+      std::make_unique<enterprise_management::PolicyData>();
+  cloud_policy_store_.policy_->set_state(
+      enterprise_management::PolicyData::ACTIVE);
+  cloud_policy_store_.policy_map_.Set(
+      key::kAutofillAddressEnabled, POLICY_LEVEL_MANDATORY, POLICY_SCOPE_USER,
+      POLICY_SOURCE_CLOUD, std::make_unique<base::Value>(false), nullptr);
+  cloud_policy_store_.NotifyStoreLoaded();
+  base::RunLoop().RunUntilIdle();
+
+  ProfilePolicyConnector connector;
+  const AccountId account_id =
+      AccountId::AdFromUserEmailObjGuid("user@realm.example", "obj-guid");
+  user_manager::User* user = user_manager->AddUser(account_id);
+  user_manager->LoginUser(account_id);
+  EXPECT_EQ(user, user_manager::UserManager::Get()->GetPrimaryUser());
+  connector.Init(user, &schema_registry_, cloud_policy_manager_.get(),
+                 &cloud_policy_store_,
+                 g_browser_process->browser_policy_connector(), false);
+  EXPECT_TRUE(connector.IsManaged());
+
+  EXPECT_FALSE(connector.policy_service()->IsInitializationComplete(
+      POLICY_DOMAIN_CHROME));
+
+  PolicyServiceInitializedWaiter(connector.policy_service(),
+                                 POLICY_DOMAIN_CHROME)
+      .Wait();
+
+  PolicyNamespace chrome_ns(POLICY_DOMAIN_CHROME, std::string());
+  const base::Value* profile_policy_value =
+      connector.policy_service()->GetPolicies(chrome_ns).GetValue(
+          key::kAutofillAddressEnabled);
+  ASSERT_TRUE(profile_policy_value);
+  EXPECT_FALSE(profile_policy_value->GetBool());
+
+  const base::Value* proxied_policy_value =
+      g_browser_process->policy_service()->GetPolicies(chrome_ns).GetValue(
+          key::kAutofillAddressEnabled);
+  ASSERT_TRUE(proxied_policy_value);
+  EXPECT_FALSE(proxied_policy_value->GetBool());
+
+  // Cleanup.
+  connector.Shutdown();
+}
 #endif  // defined(OS_CHROMEOS)
 
 TEST_F(ProfilePolicyConnectorTest, IsProfilePolicy) {
+  MockConfigurationPolicyProvider mock_platform_provider;
+  EXPECT_CALL(mock_platform_provider, IsInitializationComplete(_))
+      .WillRepeatedly(Return(true));
+
   ProfilePolicyConnector connector;
+  connector.SetPlatformPolicyProviderForTesting(&mock_platform_provider);
   connector.Init(nullptr /* user */, &schema_registry_,
                  cloud_policy_manager_.get(), &cloud_policy_store_,
                  g_browser_process->browser_policy_connector(), false);
@@ -158,7 +257,7 @@
   map.Set(key::kAutofillAddressEnabled, POLICY_LEVEL_MANDATORY,
           POLICY_SCOPE_USER, POLICY_SOURCE_CLOUD,
           std::make_unique<base::Value>(true), nullptr);
-  mock_provider_.UpdateChromePolicy(map);
+  mock_platform_provider.UpdateChromePolicy(map);
   EXPECT_FALSE(connector.IsProfilePolicy(key::kAutofillAddressEnabled));
   value = connector.policy_service()->GetPolicies(chrome_ns).GetValue(
       key::kAutofillAddressEnabled);
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 3c09b76..d1c60be 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -35,6 +35,7 @@
 #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
 #include "chrome/browser/media/webrtc/media_stream_devices_controller.h"
 #include "chrome/browser/media/webrtc/system_media_capture_permissions_stats_mac.h"
+#include "chrome/browser/memory/enterprise_memory_limit_pref_observer.h"
 #include "chrome/browser/metrics/chrome_metrics_service_client.h"
 #include "chrome/browser/net/net_error_tab_helper.h"
 #include "chrome/browser/net/prediction_options.h"
@@ -603,6 +604,7 @@
   IntranetRedirectDetector::RegisterPrefs(registry);
   language::GeoLanguageProvider::RegisterLocalStatePrefs(registry);
   language::UlpLanguageCodeLocator::RegisterLocalStatePrefs(registry);
+  memory::EnterpriseMemoryLimitPrefObserver::RegisterPrefs(registry);
   network_time::NetworkTimeTracker::RegisterPrefs(registry);
   OriginTrialPrefs::RegisterPrefs(registry);
   password_manager::PasswordManager::RegisterLocalPrefs(registry);
diff --git a/chrome/browser/previews/previews_lite_page_redirect_url_loader_interceptor_unittest.cc b/chrome/browser/previews/previews_lite_page_redirect_url_loader_interceptor_unittest.cc
index df3bc73..a20b2f9 100644
--- a/chrome/browser/previews/previews_lite_page_redirect_url_loader_interceptor_unittest.cc
+++ b/chrome/browser/previews/previews_lite_page_redirect_url_loader_interceptor_unittest.cc
@@ -87,7 +87,7 @@
                        net::HttpStatusCode code,
                        int net_error) {
     test_url_loader_factory_.AddResponse(
-        url, network::CreateResourceResponseHead(code), data,
+        url, network::CreateURLResponseHead(code), data,
         network::URLLoaderCompletionStatus(net_error));
   }
 
@@ -95,7 +95,7 @@
                         net::HttpStatusCode code,
                         int net_error) {
     test_url_loader_factory_.AddResponse(
-        url, network::CreateResourceResponseHead(code), "data",
+        url, network::CreateURLResponseHead(code), "data",
         network::URLLoaderCompletionStatus(net_error));
   }
 
diff --git a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc
index 36a6b56..f182c0a 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc
+++ b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.cc
@@ -231,9 +231,10 @@
 }
 
 cloud_print::mojom::CloudPrint& CloudPrintProxyService::GetCloudPrintProxy() {
-  if (!cloud_print_proxy_ || cloud_print_proxy_.encountered_error()) {
+  if (!cloud_print_proxy_ || !cloud_print_proxy_.is_connected()) {
+    cloud_print_proxy_.reset();
     GetServiceProcessControl()->remote_interfaces().GetInterface(
-        &cloud_print_proxy_);
+        cloud_print_proxy_.BindNewPipeAndPassReceiver());
   }
   return *cloud_print_proxy_;
 }
diff --git a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.h b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.h
index 32cf5b39..bff6a94d 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_proxy_service.h
+++ b/chrome/browser/printing/cloud_print/cloud_print_proxy_service.h
@@ -17,6 +17,7 @@
 #include "chrome/common/cloud_print.mojom.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "components/prefs/pref_change_registrar.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "printing/buildflags/buildflags.h"
 
 #if !BUILDFLAG(ENABLE_PRINT_PREVIEW) || defined(OS_CHROMEOS)
@@ -98,7 +99,7 @@
   // For watching for connector policy changes.
   PrefChangeRegistrar pref_change_registrar_;
 
-  cloud_print::mojom::CloudPrintPtr cloud_print_proxy_;
+  mojo::Remote<cloud_print::mojom::CloudPrint> cloud_print_proxy_;
 
   base::WeakPtrFactory<CloudPrintProxyService> weak_factory_{this};
 
diff --git a/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc b/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc
index dd0565c..7363631 100644
--- a/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc
+++ b/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc
@@ -8,6 +8,7 @@
 
 #include <memory>
 #include <string>
+#include <utility>
 
 #include "base/bind.h"
 #include "base/command_line.h"
@@ -29,7 +30,8 @@
 #include "components/sync_preferences/testing_pref_service_syncable.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/browser_task_environment.h"
-#include "mojo/public/cpp/bindings/binding_set.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/receiver_set.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -92,8 +94,9 @@
 
 class MockCloudPrintProxy : public cloud_print::mojom::CloudPrint {
  public:
-  void AddBinding(cloud_print::mojom::CloudPrintRequest request) {
-    bindings_.AddBinding(this, std::move(request));
+  void AddReceiver(
+      mojo::PendingReceiver<cloud_print::mojom::CloudPrint> receiver) {
+    receivers_.Add(this, std::move(receiver));
   }
 
   void ReturnDisabledInfo() {
@@ -109,11 +112,11 @@
   }
 
   bool has_been_enabled() {
-    bindings_.FlushForTesting();
+    receivers_.FlushForTesting();
     return enabled_;
   }
   bool has_been_disabled() {
-    bindings_.FlushForTesting();
+    receivers_.FlushForTesting();
     return disabled_;
   }
 
@@ -134,7 +137,7 @@
     enabled_ = true;
   }
 
-  mojo::BindingSet<cloud_print::mojom::CloudPrint> bindings_;
+  mojo::ReceiverSet<cloud_print::mojom::CloudPrint> receivers_;
 
   bool cloud_proxy_info_expectation_set_ = false;
   cloud_print::CloudPrintProxyInfo cloud_proxy_info_;
@@ -193,8 +196,9 @@
 
  private:
   void HandleCloudPrintProxyRequest(mojo::ScopedMessagePipeHandle handle) {
-    mock_proxy_.AddBinding(
-        cloud_print::mojom::CloudPrintRequest(std::move(handle)));
+    mock_proxy_.AddReceiver(
+        mojo::PendingReceiver<cloud_print::mojom::CloudPrint>(
+            std::move(handle)));
   }
 
   MockServiceProcessControl process_control_;
diff --git a/chrome/browser/printing/cloud_print/privet_http_unittest.cc b/chrome/browser/printing/cloud_print/privet_http_unittest.cc
index 84fb22c6..b15d7c3 100644
--- a/chrome/browser/printing/cloud_print/privet_http_unittest.cc
+++ b/chrome/browser/printing/cloud_print/privet_http_unittest.cc
@@ -323,7 +323,7 @@
                           net::HttpStatusCode http_status = net::HTTP_OK) {
     return test_url_loader_factory_.SimulateResponseForPendingRequest(
         request_url, network::URLLoaderCompletionStatus(net::OK),
-        network::CreateResourceResponseHead(http_status), content);
+        network::CreateURLResponseHead(http_status), content);
   }
 
   std::string GetUploadDataAsNormalizedJSON(const GURL& url) {
diff --git a/chrome/browser/printing/cloud_print/privet_notifications_unittest.cc b/chrome/browser/printing/cloud_print/privet_notifications_unittest.cc
index 3293ddc..d73190d 100644
--- a/chrome/browser/printing/cloud_print/privet_notifications_unittest.cc
+++ b/chrome/browser/printing/cloud_print/privet_notifications_unittest.cc
@@ -104,7 +104,7 @@
   bool SuccessfulResponseToInfo(const std::string& response) {
     return test_url_loader_factory_.SimulateResponseForPendingRequest(
         GURL(kDeviceInfoURL), network::URLLoaderCompletionStatus(net::OK),
-        network::CreateResourceResponseHead(net::HTTP_OK), response);
+        network::CreateURLResponseHead(net::HTTP_OK), response);
   }
 
  protected:
@@ -168,7 +168,7 @@
   notification_listener_->DeviceChanged(kExampleDeviceName, description_);
   EXPECT_TRUE(test_url_loader_factory_.SimulateResponseForPendingRequest(
       GURL(kDeviceInfoURL), network::URLLoaderCompletionStatus(net::OK),
-      network::CreateResourceResponseHead(net::HTTP_NOT_FOUND),
+      network::CreateURLResponseHead(net::HTTP_NOT_FOUND),
       /*content=*/""));
 }
 
diff --git a/chrome/browser/profile_resetter/profile_resetter_unittest.cc b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
index 69fcb03..19a5286 100644
--- a/chrome/browser/profile_resetter/profile_resetter_unittest.cc
+++ b/chrome/browser/profile_resetter/profile_resetter_unittest.cc
@@ -754,7 +754,7 @@
 TEST_F(ConfigParserTest, NoConnectivity) {
   const GURL url("http://test");
   test_url_loader_factory().AddResponse(
-      url, network::ResourceResponseHead(), "",
+      url, network::mojom::URLResponseHead::New(), "",
       network::URLLoaderCompletionStatus(net::HTTP_INTERNAL_SERVER_ERROR));
 
   std::unique_ptr<BrandcodeConfigFetcher> fetcher = WaitForRequest(GURL(url));
@@ -769,14 +769,15 @@
   ReplaceString(&xml_config,
                 "placeholder_for_id",
                 "abbaabbaabbaabbaabbaabbaabbaabba");
-  network::ResourceResponseHead head;
+  auto head = network::mojom::URLResponseHead::New();
   std::string headers("HTTP/1.1 200 OK\nContent-type: text/xml\n\n");
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
       net::HttpUtil::AssembleRawHeaders(headers));
-  head.mime_type = "text/xml";
+  head->mime_type = "text/xml";
   network::URLLoaderCompletionStatus status;
   status.decoded_body_length = xml_config.size();
-  test_url_loader_factory().AddResponse(url, head, xml_config, status);
+  test_url_loader_factory().AddResponse(url, std::move(head), xml_config,
+                                        status);
 
   std::unique_ptr<BrandcodeConfigFetcher> fetcher = WaitForRequest(GURL(url));
   std::unique_ptr<BrandcodedDefaultSettings> settings = fetcher->GetSettings();
diff --git a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
index 0b06d08..6b0033e8 100644
--- a/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
+++ b/chrome/browser/profiles/chrome_browser_main_extra_parts_profiles.cc
@@ -109,6 +109,7 @@
 
 #if defined(OS_CHROMEOS)
 #include "chrome/browser/chromeos/android_sms/android_sms_service_factory.h"
+#include "chrome/browser/chromeos/bluetooth/debug_logs_manager_factory.h"
 #include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h"
 #include "chrome/browser/chromeos/extensions/login_screen/login_state/session_state_changed_event_dispatcher.h"
 #include "chrome/browser/chromeos/extensions/printing_metrics/print_job_finished_event_dispatcher.h"
@@ -273,6 +274,7 @@
 #endif
 #if defined(OS_CHROMEOS)
   chromeos::AccountManagerMigratorFactory::GetInstance();
+  chromeos::bluetooth::DebugLogsManagerFactory::GetInstance();
   chromeos::CupsPrintJobManagerFactory::GetInstance();
   chromeos::CupsPrintersManagerFactory::GetInstance();
   chromeos::PrintJobHistoryServiceFactory::GetInstance();
diff --git a/chrome/browser/resources/bluetooth_internals/BUILD.gn b/chrome/browser/resources/bluetooth_internals/BUILD.gn
index aac6bd3..8c3a051f 100644
--- a/chrome/browser/resources/bluetooth_internals/BUILD.gn
+++ b/chrome/browser/resources/bluetooth_internals/BUILD.gn
@@ -34,7 +34,6 @@
 
   deps = [
     "//chrome/browser/ui/webui/bluetooth_internals:mojo_bindings_js_library_for_compile",
-    "//ui/webui/resources/cr_elements/cr_toggle:cr_toggle",
     "//ui/webui/resources/js:cr",
     "//ui/webui/resources/js:util",
     "//ui/webui/resources/js/cr/ui:array_data_model",
diff --git a/chrome/browser/resources/bluetooth_internals/bluetooth_internals.html b/chrome/browser/resources/bluetooth_internals/bluetooth_internals.html
index a7946d5..33381cb 100644
--- a/chrome/browser/resources/bluetooth_internals/bluetooth_internals.html
+++ b/chrome/browser/resources/bluetooth_internals/bluetooth_internals.html
@@ -10,7 +10,6 @@
   <link rel="stylesheet" href="chrome://resources/css/spinner.css">
   <link rel="stylesheet" href="bluetooth_internals.css">
 
-  <link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
   <link rel="import" href="chrome://resources/html/action_link.html">
   <link rel="import" href="chrome://resources/html/cr/ui.html">
   <link rel="import" href="chrome://resources/html/cr/event_target.html">
diff --git a/chrome/browser/resources/bluetooth_internals/debug_log_page.js b/chrome/browser/resources/bluetooth_internals/debug_log_page.js
index e300cbf..5c13a39 100644
--- a/chrome/browser/resources/bluetooth_internals/debug_log_page.js
+++ b/chrome/browser/resources/bluetooth_internals/debug_log_page.js
@@ -24,8 +24,8 @@
        */
       this.debugLogsChangeHandler_ = null;
 
-      /** @private {?CrToggleElement} */
-      this.toggleElement_ = null;
+      /** @private {?HTMLInputElement} */
+      this.inputElement_ = null;
 
       /** @private {!HTMLDivElement} */
       this.debugContainer_ =
@@ -33,7 +33,7 @@
 
       bluetoothInternalsHandler.getDebugLogsChangeHandler().then((params) => {
         if (params.handler) {
-          this.setUpToggle(params.handler, params.initialToggleValue);
+          this.setUpInput(params.handler, params.initialToggleValue);
         } else {
           this.debugContainer_.textContent = LOGS_NOT_SUPPORTED_STRING;
         }
@@ -42,22 +42,23 @@
 
     /**
      * @param {!mojom.DebugLogsChangeHandlerRemote} handler
-     * @param {boolean} initialToggleValue
+     * @param {boolean} initialInputValue
      */
-    setUpToggle(handler, initialToggleValue) {
+    setUpInput(handler, initialInputValue) {
       this.debugLogsChangeHandler_ = handler;
 
-      this.toggleElement_ =
-          /** @type {!CrToggleElement} */ (document.createElement('cr-toggle'));
-      this.toggleElement_.checked = initialToggleValue;
-      this.toggleElement_.addEventListener(
+      this.inputElement_ =
+          /** @type {!HTMLInputElement} */ (document.createElement('input'));
+      this.inputElement_.setAttribute('type', 'checkbox');
+      this.inputElement_.checked = initialInputValue;
+      this.inputElement_.addEventListener(
           'change', this.onToggleChange.bind(this));
-      this.debugContainer_.appendChild(this.toggleElement_);
+      this.debugContainer_.appendChild(this.inputElement_);
     }
 
     onToggleChange() {
       this.debugLogsChangeHandler_.changeDebugLogsState(
-          this.toggleElement_.checked);
+          this.inputElement_.checked);
     }
   }
 
diff --git a/chrome/browser/resources/chromeos/login/network_select_login.js b/chrome/browser/resources/chromeos/login/network_select_login.js
index 716d874..47b1e7c 100644
--- a/chrome/browser/resources/chromeos/login/network_select_login.js
+++ b/chrome/browser/resources/chromeos/login/network_select_login.js
@@ -328,16 +328,15 @@
       var oncType = OncMojo.getNetworkTypeString(networkState.type);
       var guid = networkState.guid;
 
+      var shouldShowNetworkDetails = isConnected ||
+          networkState.connectionState ==
+              chromeos.networkConfig.mojom.ConnectionStateType.kConnecting;
       // Cellular should normally auto connect. If it is selected, show the
       // details UI since there is no configuration UI for Cellular.
-      if (networkState.type ==
-          chromeos.networkConfig.mojom.NetworkType.kCellular) {
-        chrome.send('showNetworkDetails', [oncType, guid]);
-        return;
-      }
+      shouldShowNetworkDetails |= networkState.type ==
+          chromeos.networkConfig.mojom.NetworkType.kCellular;
 
-      // Allow proxy to be set for connected networks.
-      if (isConnected) {
+      if (shouldShowNetworkDetails) {
         chrome.send('showNetworkDetails', [oncType, guid]);
         return;
       }
diff --git a/chrome/browser/resources/print_preview/data/model.js b/chrome/browser/resources/print_preview/data/model.js
index 114cc16..8094143 100644
--- a/chrome/browser/resources/print_preview/data/model.js
+++ b/chrome/browser/resources/print_preview/data/model.js
@@ -709,8 +709,12 @@
     this.setSettingPath_('fitToPage.unavailableValue', !isSaveAsPDF);
     this.setSettingPath_(
         'fitToPage.available',
-        !knownSizeToSaveAsPdf && !this.documentSettings.isModifiable);
-    this.setSettingPath_('scaling.available', !knownSizeToSaveAsPdf);
+        !knownSizeToSaveAsPdf && this.documentSettings.isPdf);
+    this.setSettingPath_(
+        'scaling.available',
+        !knownSizeToSaveAsPdf &&
+            (this.documentSettings.isModifiable ||
+             this.documentSettings.isPdf));
     const caps = this.destination && this.destination.capabilities ?
         this.destination.capabilities.printer :
         null;
diff --git a/chrome/browser/resources/print_preview/ui/margin_control.js b/chrome/browser/resources/print_preview/ui/margin_control.js
index 346c630..0e9dca3 100644
--- a/chrome/browser/resources/print_preview/ui/margin_control.js
+++ b/chrome/browser/resources/print_preview/ui/margin_control.js
@@ -192,10 +192,10 @@
     const validationRegex =
         new RegExp(`^-?(?:${whole}${fractional}?|${fractional})$`);
     if (validationRegex.test(value)) {
-      // Replacing decimal point with the dot symbol and removing thousands
-      // marker in order to use parseFloat() properly.
-      value =
-          value.replace(decimal, '.').replace(new RegExp(thousands, 'g'), '');
+      // Removing thousands delimiters and replacing the decimal delimiter with
+      // the dot symbol in order to use parseFloat() properly.
+      value = value.replace(new RegExp(`\\${thousands}`, 'g'), '')
+                  .replace(decimal, '.');
       return this.measurementSystem.convertToPoints(parseFloat(value));
     }
     return null;
diff --git a/chrome/browser/resources/settings/controls/controlled_button.html b/chrome/browser/resources/settings/controls/controlled_button.html
index af32809..79fb7d2 100644
--- a/chrome/browser/resources/settings/controls/controlled_button.html
+++ b/chrome/browser/resources/settings/controls/controlled_button.html
@@ -42,7 +42,7 @@
       }
     </style>
 
-    <cr-button class$="[[getClass_(actionButton)]]"
+    <cr-button class$="[[actionClass_]]"
       disabled="[[!buttonEnabled_(enforced_, disabled)]]">
       [[label]]
     </cr-button>
diff --git a/chrome/browser/resources/settings/controls/controlled_button.js b/chrome/browser/resources/settings/controls/controlled_button.js
index 43f07fd..e751237 100644
--- a/chrome/browser/resources/settings/controls/controlled_button.js
+++ b/chrome/browser/resources/settings/controls/controlled_button.js
@@ -11,11 +11,6 @@
   ],
 
   properties: {
-    actionButton: {
-      type: Boolean,
-      value: false,
-    },
-
     endJustified: {
       type: Boolean,
       value: false,
@@ -31,6 +26,12 @@
     },
 
     /** @private */
+    actionClass_: {
+      type: String,
+      value: ''
+    },
+
+    /** @private */
     enforced_: {
       type: Boolean,
       computed: 'isPrefEnforced(pref.*)',
@@ -38,6 +39,18 @@
     },
   },
 
+  /** @override */
+  attached: function() {
+    if (this.classList.contains('action-button')) {
+      this.actionClass_ = 'action-button';
+    }
+  },
+
+  /** Focus on the inner cr-button. */
+  focus: function() {
+    this.$$('cr-button').focus();
+  },
+
   /**
    * @param {!Event} e
    * @private
@@ -49,15 +62,6 @@
   },
 
   /**
-   * @param {!boolean} actionButton
-   * @return {string} Class of the cr-button.
-   * @private
-   */
-  getClass_: function(actionButton) {
-    return actionButton ? 'action-button' : '';
-  },
-
-  /**
    * @param {!boolean} enforced
    * @param {!boolean} disabled
    * @return {boolean} True if the button should be enabled.
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.html b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
index 60b88f0e..7fc01a8 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.html
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.html
@@ -117,7 +117,8 @@
       </cr-button>
       <!-- Use policy properties from vpn_config_allowed to indicate when that
            pref disables buttons in this row. -->
-      <controlled-button id="connect" action-button on-click="onConnectTap_"
+      <controlled-button id="connect" class="action-button"
+          on-click="onConnectTap_"
           hidden$="[[!showConnect_(managedProperties_, globalPolicy,
               managedNetworkAvailable)]]"
           disabled="[[!enableConnect_(managedProperties_, defaultNetwork,
@@ -127,7 +128,7 @@
           pref="[[getFakeVpnConfigPrefForEnforcement_(managedProperties_,
               prefs.vpn_config_allowed)]]">
       </controlled-button>
-      <controlled-button id="disconnect" action-button
+      <controlled-button id="disconnect" class="action-button"
           on-click="onDisconnectTap_"
           hidden$="[[!showDisconnect_(managedProperties_)]]"
           label="$i18n{networkButtonDisconnect}"
diff --git a/chrome/browser/resources/settings/internet_page/internet_detail_page.js b/chrome/browser/resources/settings/internet_page/internet_detail_page.js
index 4dd3706..c1050ab0 100644
--- a/chrome/browser/resources/settings/internet_page/internet_detail_page.js
+++ b/chrome/browser/resources/settings/internet_page/internet_detail_page.js
@@ -170,6 +170,7 @@
   },
 
   observers: [
+    'handleDeviceStateChange_(deviceState_.*)',
     'updateAlwaysOnVpnPrefValue_(prefs.arc.vpn.always_on.*)',
     'updateAlwaysOnVpnPrefEnforcement_(managedProperties_,' +
         'prefs.vpn_config_allowed.*)',
@@ -343,10 +344,9 @@
     if (!this.didSetFocus_) {
       // Focus a button once the initial state is set.
       this.didSetFocus_ = true;
-      const button = this.$$('#titleDiv .action-button:not([hidden])') ||
-          this.$$('#titleDiv cr-button:not([hidden])');
+      const button = this.$$('#titleDiv .action-button:not([hidden])');
       if (button) {
-        setTimeout(() => button.focus());
+        Polymer.RenderStatus.afterNextRender(this, () => button.focus());
       }
     }
 
@@ -366,6 +366,10 @@
       return;
     }
     this.networkConfig_.getDeviceStateList().then(response => {
+      if (!this.managedProperties_) {
+        return;
+      }
+
       const devices = response.result;
       this.deviceState_ =
           devices.find(device => device.type == this.managedProperties_.type) ||
@@ -495,7 +499,7 @@
       this.close();
     }
     this.propertiesReceived_ = true;
-    this.outOfRange_ = false;
+    this.outOfRange_ = !this.isDeviceStateEnabled_();
     if (!this.deviceState_) {
       this.getDeviceState_();
     }
@@ -533,7 +537,7 @@
     this.managedProperties_ = managedProperties;
 
     this.propertiesReceived_ = true;
-    this.outOfRange_ = false;
+    this.outOfRange_ = !this.isDeviceStateEnabled_();
   },
 
   /**
@@ -980,6 +984,13 @@
   },
 
   /** @private */
+  handleDeviceStateChange_: function() {
+    // Consider the network out of range if its associated device is not enabled
+    // (e.g., a Wi-Fi network would be out of range if Wi-Fi is off).
+    this.outOfRange_ |= !this.isDeviceStateEnabled_();
+  },
+
+  /** @private */
   updateAlwaysOnVpnPrefValue_: function() {
     this.alwaysOnVpn_.value = this.prefs.arc && this.prefs.arc.vpn &&
         this.prefs.arc.vpn.always_on && this.prefs.arc.vpn.always_on.lockdown &&
@@ -1636,5 +1647,12 @@
     }
     return true;
   },
+
+  /** @return {boolean} */
+  isDeviceStateEnabled_: function() {
+    return !!this.deviceState_ &&
+        this.deviceState_.deviceState ==
+        chromeos.networkConfig.mojom.DeviceStateType.kEnabled;
+  },
 });
 })();
diff --git a/chrome/browser/safe_browsing/certificate_reporting_service_unittest.cc b/chrome/browser/safe_browsing/certificate_reporting_service_unittest.cc
index d2db600..7154215 100644
--- a/chrome/browser/safe_browsing/certificate_reporting_service_unittest.cc
+++ b/chrome/browser/safe_browsing/certificate_reporting_service_unittest.cc
@@ -220,7 +220,7 @@
   const GURL kFailureURL("https://www.foo.com/");
 
   test_url_loader_factory()->AddResponse(
-      kFailureURL, network::ResourceResponseHead(), std::string(),
+      kFailureURL, network::mojom::URLResponseHead::New(), std::string(),
       network::URLLoaderCompletionStatus(net::ERR_SSL_PROTOCOL_ERROR));
 
   CertificateErrorReporter* certificate_error_reporter =
@@ -320,7 +320,7 @@
   const GURL kFailureURL("https://www.foo.com/");
 
   test_url_loader_factory()->AddResponse(
-      kFailureURL, network::ResourceResponseHead(), std::string(),
+      kFailureURL, network::mojom::URLResponseHead::New(), std::string(),
       network::URLLoaderCompletionStatus(net::ERR_SSL_PROTOCOL_ERROR));
 
   CertificateErrorReporter* certificate_error_reporter =
diff --git a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_fetcher_win_unittest.cc b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_fetcher_win_unittest.cc
index 0cb6de0..5b11d678 100644
--- a/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_fetcher_win_unittest.cc
+++ b/chrome/browser/safe_browsing/chrome_cleaner/chrome_cleaner_fetcher_win_unittest.cc
@@ -100,7 +100,7 @@
   // For this test, just use any http response code other than net::HTTP_OK
   // and net::HTTP_NOT_FOUND.
   test_url_loader_factory_.AddResponse(
-      GetSRTDownloadURL(), network::ResourceResponseHead(), "contents",
+      GetSRTDownloadURL(), network::mojom::URLResponseHead::New(), "contents",
       network::URLLoaderCompletionStatus(net::ERR_ADDRESS_INVALID));
 
   StartFetch();
diff --git a/chrome/browser/safe_browsing/client_side_detection_service_unittest.cc b/chrome/browser/safe_browsing/client_side_detection_service_unittest.cc
index a89fb393..61b15fe 100644
--- a/chrome/browser/safe_browsing/client_side_detection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/client_side_detection_service_unittest.cc
@@ -127,7 +127,7 @@
                    int net_error) {
     if (net_error != net::OK) {
       test_url_loader_factory_.AddResponse(
-          url, network::ResourceResponseHead(), std::string(),
+          url, network::mojom::URLResponseHead::New(), std::string(),
           network::URLLoaderCompletionStatus(net_error));
       return;
     }
diff --git a/chrome/browser/safe_browsing/client_side_model_loader_unittest.cc b/chrome/browser/safe_browsing/client_side_model_loader_unittest.cc
index bae6022..d3fc599 100644
--- a/chrome/browser/safe_browsing/client_side_model_loader_unittest.cc
+++ b/chrome/browser/safe_browsing/client_side_model_loader_unittest.cc
@@ -97,7 +97,7 @@
     if (net_error != net::OK) {
       network::URLLoaderCompletionStatus status;
       test_url_loader_factory_.AddResponse(
-          model_url_, network::ResourceResponseHead(), std::string(),
+          model_url_, network::mojom::URLResponseHead::New(), std::string(),
           network::URLLoaderCompletionStatus(net_error));
       return;
     }
diff --git a/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc b/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
index d273c7434..d04cb0ba 100644
--- a/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
+++ b/chrome/browser/safe_browsing/download_protection/download_protection_service_unittest.cc
@@ -395,7 +395,7 @@
       network::URLLoaderCompletionStatus status;
       sb_service_->test_url_loader_factory()->AddResponse(
           PPAPIDownloadRequest::GetDownloadRequestUrl(),
-          network::ResourceResponseHead(), std::string(),
+          network::mojom::URLResponseHead::New(), std::string(),
           network::URLLoaderCompletionStatus(net_error));
       return;
     }
diff --git a/chrome/browser/safe_browsing/threat_details_unittest.cc b/chrome/browser/safe_browsing/threat_details_unittest.cc
index 8b0c098a..0ebb2fcb 100644
--- a/chrome/browser/safe_browsing/threat_details_unittest.cc
+++ b/chrome/browser/safe_browsing/threat_details_unittest.cc
@@ -375,15 +375,16 @@
   void WriteCacheEntry(const std::string& url,
                        const std::string& headers,
                        const std::string& content) {
-    network::ResourceResponseHead head;
-    head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+    auto head = network::mojom::URLResponseHead::New();
+    head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
         net::HttpUtil::AssembleRawHeaders(headers));
-    head.remote_endpoint = net::IPEndPoint(net::IPAddress(1, 2, 3, 4), 80);
-    head.mime_type = "text/html";
+    head->remote_endpoint = net::IPEndPoint(net::IPAddress(1, 2, 3, 4), 80);
+    head->mime_type = "text/html";
     network::URLLoaderCompletionStatus status;
     status.decoded_body_length = content.size();
 
-    test_url_loader_factory_.AddResponse(GURL(url), head, content, status);
+    test_url_loader_factory_.AddResponse(GURL(url), std::move(head), content,
+                                         status);
   }
 
   void SimulateFillCache(const std::string& url) {
@@ -1736,10 +1737,10 @@
 
   // Simulate no cache entry found.
   test_url_loader_factory_.AddResponse(
-      GURL(kThreatURL), network::ResourceResponseHead(), std::string(),
+      GURL(kThreatURL), network::mojom::URLResponseHead::New(), std::string(),
       network::URLLoaderCompletionStatus(net::ERR_CACHE_MISS));
   test_url_loader_factory_.AddResponse(
-      GURL(kLandingURL), network::ResourceResponseHead(), std::string(),
+      GURL(kLandingURL), network::mojom::URLResponseHead::New(), std::string(),
       network::URLLoaderCompletionStatus(net::ERR_CACHE_MISS));
 
   // The cache collection starts after the IPC from the DOM is fired.
diff --git a/chrome/browser/search/background/ntp_background_service_unittest.cc b/chrome/browser/search/background/ntp_background_service_unittest.cc
index 1c7dcff..e50d49b8 100644
--- a/chrome/browser/search/background/ntp_background_service_unittest.cc
+++ b/chrome/browser/search/background/ntp_background_service_unittest.cc
@@ -47,7 +47,7 @@
 
   void SetUpResponseWithNetworkError(const GURL& load_url) {
     test_url_loader_factory_.AddResponse(
-        load_url, network::ResourceResponseHead(), std::string(),
+        load_url, network::mojom::URLResponseHead::New(), std::string(),
         network::URLLoaderCompletionStatus(net::HTTP_NOT_FOUND));
   }
 
diff --git a/chrome/browser/search/one_google_bar/one_google_bar_loader_impl_unittest.cc b/chrome/browser/search/one_google_bar/one_google_bar_loader_impl_unittest.cc
index 538f1ebc..ab6a1b2e 100644
--- a/chrome/browser/search/one_google_bar/one_google_bar_loader_impl_unittest.cc
+++ b/chrome/browser/search/one_google_bar/one_google_bar_loader_impl_unittest.cc
@@ -82,7 +82,7 @@
   void SetUpResponseWithNetworkError() {
     test_url_loader_factory_.AddResponse(
         one_google_bar_loader_->GetLoadURLForTesting(),
-        network::ResourceResponseHead(), std::string(),
+        network::mojom::URLResponseHead::New(), std::string(),
         network::URLLoaderCompletionStatus(net::HTTP_NOT_FOUND));
   }
 
diff --git a/chrome/browser/search/promos/promo_service_unittest.cc b/chrome/browser/search/promos/promo_service_unittest.cc
index d78456b..d448358 100644
--- a/chrome/browser/search/promos/promo_service_unittest.cc
+++ b/chrome/browser/search/promos/promo_service_unittest.cc
@@ -56,7 +56,7 @@
 
   void SetUpResponseWithNetworkError(const GURL& load_url) {
     test_url_loader_factory_.AddResponse(
-        load_url, network::ResourceResponseHead(), std::string(),
+        load_url, network::mojom::URLResponseHead::New(), std::string(),
         network::URLLoaderCompletionStatus(net::HTTP_NOT_FOUND));
   }
 
diff --git a/chrome/browser/search/search_suggest/search_suggest_loader_impl_unittest.cc b/chrome/browser/search/search_suggest/search_suggest_loader_impl_unittest.cc
index 7b1972a..93dfa8c 100644
--- a/chrome/browser/search/search_suggest/search_suggest_loader_impl_unittest.cc
+++ b/chrome/browser/search/search_suggest/search_suggest_loader_impl_unittest.cc
@@ -83,7 +83,7 @@
   void SetUpResponseWithNetworkError() {
     test_url_loader_factory_.AddResponse(
         search_suggest_loader_->GetLoadURLForTesting(),
-        network::ResourceResponseHead(), std::string(),
+        network::mojom::URLResponseHead::New(), std::string(),
         network::URLLoaderCompletionStatus(net::HTTP_NOT_FOUND));
   }
 
diff --git a/chrome/browser/service_process/service_process_control_browsertest.cc b/chrome/browser/service_process/service_process_control_browsertest.cc
index 64aea3e..0ea2f64 100644
--- a/chrome/browser/service_process/service_process_control_browsertest.cc
+++ b/chrome/browser/service_process/service_process_control_browsertest.cc
@@ -30,6 +30,7 @@
 #include "content/public/common/content_paths.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/test/test_utils.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
 #if defined(OS_WIN)
@@ -174,9 +175,9 @@
 
   // Make sure we are connected to the service process.
   ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
-  cloud_print::mojom::CloudPrintPtr cloud_print_proxy;
+  mojo::Remote<cloud_print::mojom::CloudPrint> cloud_print_proxy;
   ServiceProcessControl::GetInstance()->remote_interfaces().GetInterface(
-      &cloud_print_proxy);
+      cloud_print_proxy.BindNewPipeAndPassReceiver());
   base::RunLoop run_loop;
   cloud_print_proxy->GetCloudPrintProxyInfo(
       base::BindOnce([](base::OnceClosure done, bool, const std::string&,
@@ -193,9 +194,9 @@
 
   // Make sure we are connected to the service process.
   ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
-  cloud_print::mojom::CloudPrintPtr cloud_print_proxy;
+  mojo::Remote<cloud_print::mojom::CloudPrint> cloud_print_proxy;
   ServiceProcessControl::GetInstance()->remote_interfaces().GetInterface(
-      &cloud_print_proxy);
+      cloud_print_proxy.BindNewPipeAndPassReceiver());
   base::RunLoop run_loop;
   cloud_print_proxy->GetCloudPrintProxyInfo(
       base::BindOnce([](base::OnceClosure done, bool, const std::string&,
@@ -220,14 +221,15 @@
   // Make sure we are connected to the service process.
   ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
   // Send an IPC that will keep the service process alive after we disconnect.
-  cloud_print::mojom::CloudPrintPtr cloud_print_proxy;
+  mojo::Remote<cloud_print::mojom::CloudPrint> cloud_print_proxy;
   ServiceProcessControl::GetInstance()->remote_interfaces().GetInterface(
-      &cloud_print_proxy);
+      cloud_print_proxy.BindNewPipeAndPassReceiver());
   cloud_print_proxy->EnableCloudPrintProxyWithRobot(
       "", "", "", base::Value(base::Value::Type::DICTIONARY));
 
+  cloud_print_proxy.reset();
   ServiceProcessControl::GetInstance()->remote_interfaces().GetInterface(
-      &cloud_print_proxy);
+      cloud_print_proxy.BindNewPipeAndPassReceiver());
   {
     base::RunLoop run_loop;
     cloud_print_proxy->GetCloudPrintProxyInfo(
@@ -246,8 +248,9 @@
     run_loop.Run();
   }
 
+  cloud_print_proxy.reset();
   ServiceProcessControl::GetInstance()->remote_interfaces().GetInterface(
-      &cloud_print_proxy);
+      cloud_print_proxy.BindNewPipeAndPassReceiver());
   {
     base::RunLoop run_loop;
     cloud_print_proxy->GetCloudPrintProxyInfo(
@@ -275,9 +278,9 @@
 
   // Make sure we are connected to the service process.
   ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
-  cloud_print::mojom::CloudPrintPtr cloud_print_proxy;
+  mojo::Remote<cloud_print::mojom::CloudPrint> cloud_print_proxy;
   ServiceProcessControl::GetInstance()->remote_interfaces().GetInterface(
-      &cloud_print_proxy);
+      cloud_print_proxy.BindNewPipeAndPassReceiver());
   {
     base::RunLoop run_loop;
     cloud_print_proxy->GetCloudPrintProxyInfo(
@@ -290,8 +293,9 @@
   // Launch the service process again.
   LaunchServiceProcessControlAndWait();
   ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
+  cloud_print_proxy.reset();
   ServiceProcessControl::GetInstance()->remote_interfaces().GetInterface(
-      &cloud_print_proxy);
+      cloud_print_proxy.BindNewPipeAndPassReceiver());
   {
     base::RunLoop run_loop;
     cloud_print_proxy->GetCloudPrintProxyInfo(
@@ -455,9 +459,9 @@
 
   // Make sure we are connected to the service process.
   ASSERT_TRUE(ServiceProcessControl::GetInstance()->IsConnected());
-  cloud_print::mojom::CloudPrintPtr cloud_print_proxy;
+  mojo::Remote<cloud_print::mojom::CloudPrint> cloud_print_proxy;
   ServiceProcessControl::GetInstance()->remote_interfaces().GetInterface(
-      &cloud_print_proxy);
+      cloud_print_proxy.BindNewPipeAndPassReceiver());
   base::RunLoop run_loop;
   cloud_print_proxy->GetCloudPrintProxyInfo(
       base::BindOnce([](base::OnceClosure done, bool, const std::string&,
diff --git a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory_unittest.cc b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory_unittest.cc
index 152a479..b96f352 100644
--- a/chrome/browser/signin/chrome_signin_proxying_url_loader_factory_unittest.cc
+++ b/chrome/browser/signin/chrome_signin_proxying_url_loader_factory_unittest.cc
@@ -252,21 +252,24 @@
     // referrer but we do for testing purposes.
     redirect_info.new_referrer = kTestURL.spec();
 
-    network::ResourceResponseHead redirect_head;
-    redirect_head.headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
-    redirect_head.headers->AddHeader("X-Response-1: Foo");
-    redirect_head.headers->AddHeader("X-Response-2: Bar");
+    auto redirect_head = network::mojom::URLResponseHead::New();
+    redirect_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+    redirect_head->headers->AddHeader("X-Response-1: Foo");
+    redirect_head->headers->AddHeader("X-Response-2: Bar");
 
-    network::ResourceResponseHead response_head;
-    response_head.headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
-    response_head.headers->AddHeader("X-Response-3: Foo");
-    response_head.headers->AddHeader("X-Response-4: Bar");
+    auto response_head = network::mojom::URLResponseHead::New();
+    response_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+    response_head->headers->AddHeader("X-Response-3: Foo");
+    response_head->headers->AddHeader("X-Response-4: Bar");
     std::string body("Hello.");
     network::URLLoaderCompletionStatus status;
     status.decoded_body_length = body.size();
 
-    factory()->AddResponse(kTestURL, response_head, body, status,
-                           {{redirect_info, redirect_head}});
+    network::TestURLLoaderFactory::Redirects redirects;
+    redirects.push_back({redirect_info, std::move(redirect_head)});
+
+    factory()->AddResponse(kTestURL, std::move(response_head), body, status,
+                           std::move(redirects));
   }
 
   // Wait for the request to complete and check the response.
diff --git a/chrome/browser/spellchecker/spelling_service_client_unittest.cc b/chrome/browser/spellchecker/spelling_service_client_unittest.cc
index 5441a4b..813bccf 100644
--- a/chrome/browser/spellchecker/spelling_service_client_unittest.cc
+++ b/chrome/browser/spellchecker/spelling_service_client_unittest.cc
@@ -26,7 +26,6 @@
 #include "content/public/test/browser_task_environment.h"
 #include "net/base/load_flags.h"
 #include "net/http/http_util.h"
-#include "services/network/public/cpp/resource_response.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/test/test_url_loader_factory.h"
@@ -147,8 +146,8 @@
 // misspelled words with ones suggested by the service so this test can compare
 // the corrected text with the expected results. (If there are not any
 // misspelled words, |corrected_text| should be equal to |request_text|.)
-using Redirects =
-    std::vector<std::pair<net::RedirectInfo, network::ResourceResponseHead>>;
+using Redirects = std::vector<
+    std::pair<net::RedirectInfo, network::mojom::URLResponseHeadPtr>>;
 
 TEST_P(SpellingServiceClientTest, RequestTextCheck) {
   auto test_case = GetParam();
@@ -169,19 +168,20 @@
   client_.test_url_loader_factory()->ClearResponses();
   net::HttpStatusCode http_status = test_case.response_status;
 
-  network::ResourceResponseHead head;
+  auto head = network::mojom::URLResponseHead::New();
   std::string headers(base::StringPrintf(
       "HTTP/1.1 %d %s\nContent-type: application/json\n\n",
       static_cast<int>(http_status), net::GetHttpReasonPhrase(http_status)));
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
       net::HttpUtil::AssembleRawHeaders(headers));
-  head.mime_type = "application/json";
+  head->mime_type = "application/json";
 
   network::URLLoaderCompletionStatus status;
   status.decoded_body_length = test_case.response_data.size();
   GURL expected_request_url = client_.BuildEndpointUrl(test_case.request_type);
   client_.test_url_loader_factory()->AddResponse(
-      expected_request_url, head, test_case.response_data, status, Redirects(),
+      expected_request_url, std::move(head), test_case.response_data, status,
+      Redirects(),
       network::TestURLLoaderFactory::ResponseProduceFlags::
           kSendHeadersOnNetworkError);
 
diff --git a/chrome/browser/ssl/certificate_error_reporter_unittest.cc b/chrome/browser/ssl/certificate_error_reporter_unittest.cc
index 719617a3..e715011 100644
--- a/chrome/browser/ssl/certificate_error_reporter_unittest.cc
+++ b/chrome/browser/ssl/certificate_error_reporter_unittest.cc
@@ -125,7 +125,7 @@
   const GURL report_uri("http://foo.com/bar");
 
   test_url_loader_factory_.AddResponse(
-      report_uri, network::ResourceResponseHead(), std::string(),
+      report_uri, network::mojom::URLResponseHead::New(), std::string(),
       network::URLLoaderCompletionStatus(net::ERR_CONNECTION_FAILED));
 
   CertificateErrorReporter reporter(test_shared_loader_factory_, report_uri);
diff --git a/chrome/browser/ssl/security_state_tab_helper_browsertest.cc b/chrome/browser/ssl/security_state_tab_helper_browsertest.cc
index 77dc011..d12bddf 100644
--- a/chrome/browser/ssl/security_state_tab_helper_browsertest.cc
+++ b/chrome/browser/ssl/security_state_tab_helper_browsertest.cc
@@ -520,7 +520,7 @@
           security_state::features::kMarkHttpAsParameterDangerous) {
         expected_security_level = security_state::DANGEROUS;
       } else {
-        expected_security_level = security_state::HTTP_SHOW_WARNING;
+        expected_security_level = security_state::WARNING;
       }
     }
 
@@ -1022,7 +1022,7 @@
 }
 
 // Tests that the security level of data: URLs is always downgraded to
-// HTTP_SHOW_WARNING.
+// WARNING.
 IN_PROC_BROWSER_TEST_F(SecurityStateTabHelperTest,
                        SecurityLevelDowngradedOnDataUrl) {
   content::WebContents* contents =
@@ -1036,7 +1036,7 @@
   ASSERT_TRUE(helper);
 
   ui_test_utils::NavigateToURL(browser(), GURL("data:text/html,<html></html>"));
-  EXPECT_EQ(security_state::HTTP_SHOW_WARNING, helper->GetSecurityLevel());
+  EXPECT_EQ(security_state::WARNING, helper->GetSecurityLevel());
 
   // Ensure that WebContentsObservers don't show an incorrect Form Not Secure
   // explanation. Regression test for https://crbug.com/691412.
@@ -1144,7 +1144,7 @@
 }
 
 // Tests that the security level of ftp: URLs is always downgraded to
-// HTTP_SHOW_WARNING.
+// WARNING.
 IN_PROC_BROWSER_TEST_F(SecurityStateTabHelperTest,
                        SecurityLevelDowngradedOnFtpUrl) {
   content::WebContents* contents =
@@ -1158,7 +1158,7 @@
   ASSERT_TRUE(helper);
 
   ui_test_utils::NavigateToURL(browser(), GURL("ftp://example.test/"));
-  EXPECT_EQ(security_state::HTTP_SHOW_WARNING, helper->GetSecurityLevel());
+  EXPECT_EQ(security_state::WARNING, helper->GetSecurityLevel());
 
   // Ensure that WebContentsObservers don't show an incorrect Form Not Secure
   // explanation. Regression test for https://crbug.com/691412.
@@ -1363,25 +1363,25 @@
       browser(),
       GetURLWithNonLocalHostname(embedded_test_server(),
                                  "/textinput/focus_input_on_load.html"));
-  EXPECT_EQ(security_state::HTTP_SHOW_WARNING, helper->GetSecurityLevel());
+  EXPECT_EQ(security_state::WARNING, helper->GetSecurityLevel());
 
   // Verify a value set operation isn't treated as user-input.
   EXPECT_TRUE(content::ExecuteScript(
       contents, "document.getElementById('text_id').value='v';"));
   InjectScript(contents);
   base::RunLoop().RunUntilIdle();
-  ASSERT_EQ(security_state::HTTP_SHOW_WARNING, helper->GetSecurityLevel());
+  ASSERT_EQ(security_state::WARNING, helper->GetSecurityLevel());
 
   // Verify an InsertText operation isn't treated as user-input.
   EXPECT_TRUE(content::ExecuteScript(
       contents, "document.execCommand('InsertText',false,'a');"));
   InjectScript(contents);
   base::RunLoop().RunUntilIdle();
-  ASSERT_EQ(security_state::HTTP_SHOW_WARNING, helper->GetSecurityLevel());
+  ASSERT_EQ(security_state::WARNING, helper->GetSecurityLevel());
 }
 
 // Tests that the security level of a HTTP page is downgraded from
-// HTTP_SHOW_WARNING to DANGEROUS after editing a form field in the relevant
+// WARNING to DANGEROUS after editing a form field in the relevant
 // configurations.
 IN_PROC_BROWSER_TEST_F(SecurityStateTabHelperTest,
                        SecurityLevelDowngradedAfterFileSelection) {
@@ -1401,7 +1401,7 @@
   ui_test_utils::NavigateToURL(
       browser(),
       GetURLWithNonLocalHostname(embedded_test_server(), "/file_input.html"));
-  EXPECT_EQ(security_state::HTTP_SHOW_WARNING, helper->GetSecurityLevel());
+  EXPECT_EQ(security_state::WARNING, helper->GetSecurityLevel());
 
   // Prepare a file for the upload form.
   base::FilePath file_path;
@@ -1429,7 +1429,7 @@
   // Verify that after a refresh, the DANGEROUS state is cleared.
   contents->GetController().Reload(content::ReloadType::NORMAL, false);
   content::WaitForLoadStop(contents);
-  EXPECT_EQ(security_state::HTTP_SHOW_WARNING, helper->GetSecurityLevel());
+  EXPECT_EQ(security_state::WARNING, helper->GetSecurityLevel());
 }
 
 // A Browser subclass that keeps track of messages that have been
@@ -1911,7 +1911,7 @@
       GetURLWithNonLocalHostname(embedded_test_server(),
                                  "/textinput/focus_input_on_load.html"));
 
-  EXPECT_EQ(security_state::HTTP_SHOW_WARNING, helper->GetSecurityLevel());
+  EXPECT_EQ(security_state::WARNING, helper->GetSecurityLevel());
 
   {
     // Ensure that the security level remains Dangerous in the
@@ -1951,7 +1951,7 @@
   // Verify that after a refresh, the DANGEROUS state is cleared.
   contents->GetController().Reload(content::ReloadType::NORMAL, false);
   content::WaitForLoadStop(contents);
-  EXPECT_EQ(security_state::HTTP_SHOW_WARNING, helper->GetSecurityLevel());
+  EXPECT_EQ(security_state::WARNING, helper->GetSecurityLevel());
 }
 
 IN_PROC_BROWSER_TEST_F(SecurityStateTabHelperTest,
@@ -1975,7 +1975,7 @@
       browser(),
       GetURLWithNonLocalHostname(embedded_test_server(), "/file_input.html"));
 
-  EXPECT_EQ(security_state::HTTP_SHOW_WARNING, helper->GetSecurityLevel());
+  EXPECT_EQ(security_state::WARNING, helper->GetSecurityLevel());
   SecurityStyleTestObserver observer(contents);
 
   // Prepare a file for the upload form.
@@ -2013,8 +2013,7 @@
     ui_test_utils::NavigateToURL(
         browser(),
         GetURLWithNonLocalHostname(embedded_test_server(), "/title1.html"));
-    histograms.ExpectUniqueSample(kHistogramName,
-                                  security_state::HTTP_SHOW_WARNING, 1);
+    histograms.ExpectUniqueSample(kHistogramName, security_state::WARNING, 1);
   }
 }
 
diff --git a/chrome/browser/ssl/security_state_tab_helper_unittest.cc b/chrome/browser/ssl/security_state_tab_helper_unittest.cc
index 9f4ac96..a305b64 100644
--- a/chrome/browser/ssl/security_state_tab_helper_unittest.cc
+++ b/chrome/browser/ssl/security_state_tab_helper_unittest.cc
@@ -77,7 +77,7 @@
   base::HistogramTester histograms;
   StartFormSubmissionNavigation();
   histograms.ExpectUniqueSample(kFormSubmissionSecurityLevelHistogram,
-                                security_state::HTTP_SHOW_WARNING, 1);
+                                security_state::WARNING, 1);
 }
 
 }  // namespace
diff --git a/chrome/browser/ssl/ssl_browsertest.cc b/chrome/browser/ssl/ssl_browsertest.cc
index 4caaaff..4dad191 100644
--- a/chrome/browser/ssl/ssl_browsertest.cc
+++ b/chrome/browser/ssl/ssl_browsertest.cc
@@ -125,6 +125,7 @@
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/content_switches.h"
+#include "content/public/common/network_service_util.h"
 #include "content/public/common/page_state.h"
 #include "content/public/common/service_names.mojom.h"
 #include "content/public/common/url_constants.h"
@@ -2068,7 +2069,7 @@
   ASSERT_TRUE(helper);
 
   ui_test_utils::NavigateToURL(browser(), GURL("data:text/plain,hello"));
-  EXPECT_EQ(security_state::HTTP_SHOW_WARNING, helper->GetSecurityLevel());
+  EXPECT_EQ(security_state::WARNING, helper->GetSecurityLevel());
 }
 
 // Ensure that HTTP-protocol origins are marked as Dangerous when the
@@ -5768,6 +5769,9 @@
 
 // Checks that a newly-added certificate authority is usable immediately.
 IN_PROC_BROWSER_TEST_F(SSLUITestNoCert, NewCertificateAuthority) {
+  if (!content::IsOutOfProcessNetworkService())
+    return;
+
   ASSERT_TRUE(https_server_.Start());
 
   WebContents* tab = browser()->tab_strip_model()->GetActiveWebContents();
@@ -7552,12 +7556,17 @@
   }
 
   void TearDownOnMainThread() override {
-    mojo::ScopedAllowSyncCallForTesting allow_sync_call;
+    if (content::IsOutOfProcessNetworkService()) {
+      mojo::ScopedAllowSyncCallForTesting allow_sync_call;
 
-    network::mojom::NetworkServiceTestPtr network_service_test;
-    content::GetSystemConnector()->BindInterface(
-        content::mojom::kNetworkServiceName, &network_service_test);
-    network_service_test->SetTransportSecurityStateSource(0);
+      network::mojom::NetworkServiceTestPtr network_service_test;
+      content::GetSystemConnector()->BindInterface(
+          content::mojom::kNetworkServiceName, &network_service_test);
+      network_service_test->SetTransportSecurityStateSource(0);
+    } else {
+      RunOnIOThreadBlocking(base::BindOnce(
+          &SSLPKPBrowserTest::CleanUpOnIOThread, base::Unretained(this)));
+    }
     CertVerifierBrowserTest::TearDownOnMainThread();
   }
 
@@ -7567,11 +7576,22 @@
         content::BrowserContext::GetDefaultStoragePartition(
             browser()->profile());
     partition->GetNetworkContext()->EnableStaticKeyPinningForTesting();
+    partition->FlushNetworkInterfaceForTesting();
 
-    network::mojom::NetworkServiceTestPtr network_service_test;
-    content::GetSystemConnector()->BindInterface(
-        content::mojom::kNetworkServiceName, &network_service_test);
-    network_service_test->SetTransportSecurityStateSource(reporting_port);
+    if (content::IsOutOfProcessNetworkService()) {
+      network::mojom::NetworkServiceTestPtr network_service_test;
+      content::GetSystemConnector()->BindInterface(
+          content::mojom::kNetworkServiceName, &network_service_test);
+      network_service_test->SetTransportSecurityStateSource(reporting_port);
+    } else {
+      // TODO(https://crbug.com/1008175):  This code is not threadsafe, as the
+      // network stack does not run on the IO thread. Ideally, the
+      // NetworkServiceTest object would be set up in-process on the network
+      // service's thread, and this path would be removed.
+      RunOnIOThreadBlocking(base::BindOnce(
+          &SSLPKPBrowserTest::SetTransportSecurityStateSourceOnIO,
+          base::Unretained(this), reporting_port));
+    }
   }
 
  private:
@@ -7581,6 +7601,18 @@
                            std::move(task), run_loop.QuitClosure());
     run_loop.Run();
   }
+
+  void SetTransportSecurityStateSourceOnIO(int reporting_port) {
+    transport_security_state_source_ =
+        std::make_unique<net::ScopedTransportSecurityStateSource>(
+            reporting_port);
+  }
+
+  void CleanUpOnIOThread() { transport_security_state_source_.reset(); }
+
+  // Only used when NetworkService is disabled. Accessed on IO thread.
+  std::unique_ptr<net::ScopedTransportSecurityStateSource>
+      transport_security_state_source_;
 };
 
 // Test case where a PKP report is sent.
diff --git a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc
index c4df739..7776f38 100644
--- a/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc
+++ b/chrome/browser/supervised_user/child_accounts/permission_request_creator_apiary_unittest.cc
@@ -64,14 +64,14 @@
   }
 
   void SetupResponse(net::Error error, const std::string& response) {
-    network::ResourceResponseHead head;
+    auto head = network::mojom::URLResponseHead::New();
     std::string headers("HTTP/1.1 200 OK\n\n");
-    head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+    head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
         net::HttpUtil::AssembleRawHeaders(headers));
     network::URLLoaderCompletionStatus status(error);
     status.decoded_body_length = response.size();
-    test_url_loader_factory_.AddResponse(permission_creator_->GetApiUrl(), head,
-                                         response, status);
+    test_url_loader_factory_.AddResponse(permission_creator_->GetApiUrl(),
+                                         std::move(head), response, status);
   }
 
   void CreateRequest(const GURL& url) {
diff --git a/chrome/browser/sync/test/integration/sync_test.cc b/chrome/browser/sync/test/integration/sync_test.cc
index 92bf9b5..52325c6 100644
--- a/chrome/browser/sync/test/integration/sync_test.cc
+++ b/chrome/browser/sync/test/integration/sync_test.cc
@@ -1084,11 +1084,11 @@
 
   std::string response = base::StringPrintf("HTTP/1.1 %d %s\r\n", status_code,
                                             GetHttpReasonPhrase(status_code));
-  network::ResourceResponseHead resource_response;
-  resource_response.headers =
+  auto response_head = network::mojom::URLResponseHead::New();
+  response_head->headers =
       base::MakeRefCounted<net::HttpResponseHeaders>(response);
   test_url_loader_factory_.AddResponse(
-      GaiaUrls::GetInstance()->oauth2_token_url(), resource_response,
+      GaiaUrls::GetInstance()->oauth2_token_url(), std::move(response_head),
       response_data, completion_status);
   base::RunLoop().RunUntilIdle();
 }
diff --git a/chrome/browser/ui/android/autofill/card_name_fix_flow_view_android.cc b/chrome/browser/ui/android/autofill/card_name_fix_flow_view_android.cc
index 8cbf660..2a81efce 100644
--- a/chrome/browser/ui/android/autofill/card_name_fix_flow_view_android.cc
+++ b/chrome/browser/ui/android/autofill/card_name_fix_flow_view_android.cc
@@ -6,7 +6,8 @@
 
 #include "chrome/android/chrome_jni_headers/AutofillNameFixFlowBridge_jni.h"
 #include "chrome/browser/android/resource_mapper.h"
-#include "components/autofill/core/browser/ui/payments/card_name_fix_flow_view_delegate_mobile.h"
+#include "components/autofill/core/browser/ui/payments/card_name_fix_flow_controller.h"
+#include "components/autofill/core/browser/ui/payments/card_name_fix_flow_view.h"
 #include "content/public/browser/web_contents.h"
 #include "ui/android/view_android.h"
 #include "ui/android/window_android.h"
@@ -17,13 +18,22 @@
 namespace autofill {
 
 CardNameFixFlowViewAndroid::CardNameFixFlowViewAndroid(
-    std::unique_ptr<CardNameFixFlowViewDelegateMobile> delegate,
+    CardNameFixFlowController* controller,
     content::WebContents* web_contents)
-    : delegate_(std::move(delegate)), web_contents_(web_contents) {}
+    : controller_(controller), web_contents_(web_contents) {}
 
-CardNameFixFlowViewAndroid::~CardNameFixFlowViewAndroid() {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  Java_AutofillNameFixFlowBridge_dismiss(env, java_object_);
+void CardNameFixFlowViewAndroid::OnUserAccept(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jstring>& name) {
+  controller_->OnNameAccepted(
+      base::android::ConvertJavaStringToUTF16(env, name));
+}
+
+void CardNameFixFlowViewAndroid::PromptDismissed(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj) {
+  delete this;
 }
 
 void CardNameFixFlowViewAndroid::Show() {
@@ -31,38 +41,33 @@
   ui::ViewAndroid* view_android = web_contents_->GetNativeView();
 
   ScopedJavaLocalRef<jstring> dialog_title =
-      base::android::ConvertUTF16ToJavaString(env, delegate_->GetTitleText());
+      base::android::ConvertUTF16ToJavaString(env, controller_->GetTitleText());
 
   ScopedJavaLocalRef<jstring> inferred_name =
       base::android::ConvertUTF16ToJavaString(
-          env, delegate_->GetInferredCardHolderName());
+          env, controller_->GetInferredCardholderName());
 
   ScopedJavaLocalRef<jstring> confirm = base::android::ConvertUTF16ToJavaString(
-      env, delegate_->GetSaveButtonLabel());
+      env, controller_->GetSaveButtonLabel());
 
   java_object_.Reset(Java_AutofillNameFixFlowBridge_create(
       env, reinterpret_cast<intptr_t>(this), dialog_title, inferred_name,
-      confirm, ResourceMapper::MapFromChromiumId(delegate_->GetIconId()),
+      confirm, ResourceMapper::MapFromChromiumId(controller_->GetIconId()),
       view_android->GetWindowAndroid()->GetJavaObject()));
 
   Java_AutofillNameFixFlowBridge_show(
       env, java_object_, view_android->GetWindowAndroid()->GetJavaObject());
-  delegate_->Shown();
 }
 
-void CardNameFixFlowViewAndroid::OnUserAccept(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj,
-    const JavaParamRef<jstring>& name) {
-  delegate_->Accept(base::android::ConvertJavaStringToUTF16(env, name));
+void CardNameFixFlowViewAndroid::ControllerGone() {
+  controller_ = nullptr;
+  JNIEnv* env = base::android::AttachCurrentThread();
   Java_AutofillNameFixFlowBridge_dismiss(env, java_object_);
 }
 
-void CardNameFixFlowViewAndroid::PromptDismissed(
-    JNIEnv* env,
-    const JavaParamRef<jobject>& obj) {
-  delegate_->Dismissed();
-  delete this;
+CardNameFixFlowViewAndroid::~CardNameFixFlowViewAndroid() {
+  if (controller_)
+    controller_->OnConfirmNameDialogClosed();
 }
 
 }  // namespace autofill
diff --git a/chrome/browser/ui/android/autofill/card_name_fix_flow_view_android.h b/chrome/browser/ui/android/autofill/card_name_fix_flow_view_android.h
index dc56d5d..1c86345 100644
--- a/chrome/browser/ui/android/autofill/card_name_fix_flow_view_android.h
+++ b/chrome/browser/ui/android/autofill/card_name_fix_flow_view_android.h
@@ -11,6 +11,7 @@
 #include "base/android/scoped_java_ref.h"
 #include "base/macros.h"
 #include "base/strings/string16.h"
+#include "components/autofill/core/browser/ui/payments/card_name_fix_flow_view.h"
 
 namespace content {
 class WebContents;
@@ -18,16 +19,13 @@
 
 namespace autofill {
 
-class CardNameFixFlowViewDelegateMobile;
-// This class is responsible for its destruction. Destruction is achieved by
-// calling delete when the prompt is dismissed.
-class CardNameFixFlowViewAndroid {
- public:
-  CardNameFixFlowViewAndroid(
-      std::unique_ptr<CardNameFixFlowViewDelegateMobile> delegate,
-      content::WebContents* web_contents);
+class CardNameFixFlowController;
 
-  ~CardNameFixFlowViewAndroid();
+class CardNameFixFlowViewAndroid : public CardNameFixFlowView {
+ public:
+  // |controller| must outlive |this|.
+  CardNameFixFlowViewAndroid(CardNameFixFlowController* controller,
+                             content::WebContents* web_contents);
 
   void OnUserAccept(JNIEnv* env,
                     const base::android::JavaParamRef<jobject>& obj,
@@ -35,14 +33,17 @@
   void PromptDismissed(JNIEnv* env,
                        const base::android::JavaParamRef<jobject>& obj);
 
-  void Show();
+  // CardNameFixFlowView implementation.
+  void Show() override;
+  void ControllerGone() override;
 
  private:
+  ~CardNameFixFlowViewAndroid() override;
+
   // The corresponding java object.
   base::android::ScopedJavaGlobalRef<jobject> java_object_;
 
-  std::unique_ptr<CardNameFixFlowViewDelegateMobile> delegate_;
-
+  CardNameFixFlowController* controller_;
   content::WebContents* web_contents_;
 
   DISALLOW_COPY_AND_ASSIGN(CardNameFixFlowViewAndroid);
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc
index 9a7e5d2e..7e64d8b 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.cc
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc
@@ -77,7 +77,7 @@
 #include "components/autofill/core/browser/payments/autofill_save_card_infobar_delegate_mobile.h"
 #include "components/autofill/core/browser/payments/autofill_save_card_infobar_mobile.h"
 #include "components/autofill/core/browser/ui/payments/card_expiration_date_fix_flow_view_delegate_mobile.h"
-#include "components/autofill/core/browser/ui/payments/card_name_fix_flow_view_delegate_mobile.h"
+#include "components/autofill/core/browser/ui/payments/card_name_fix_flow_view.h"
 #include "components/infobars/core/infobar.h"
 #include "ui/android/window_android.h"
 #else  // !OS_ANDROID
@@ -334,18 +334,12 @@
 #if defined(OS_ANDROID)
 void ChromeAutofillClient::ConfirmAccountNameFixFlow(
     base::OnceCallback<void(const base::string16&)> callback) {
-  std::unique_ptr<CardNameFixFlowViewDelegateMobile>
-      card_name_fix_flow_view_delegate_mobile =
-          std::make_unique<CardNameFixFlowViewDelegateMobile>(
-              GetAccountHolderName(),
-              /*upload_save_card_callback=*/std::move(callback));
-
-  // Destruction is handled by the fix flow dialog by explicitly calling delete
-  // when the prompt is dismissed.
   CardNameFixFlowViewAndroid* card_name_fix_flow_view_android =
-      new CardNameFixFlowViewAndroid(
-          std::move(card_name_fix_flow_view_delegate_mobile), web_contents());
-  card_name_fix_flow_view_android->Show();
+      new CardNameFixFlowViewAndroid(&card_name_fix_flow_controller_,
+                                     web_contents());
+  card_name_fix_flow_controller_.Show(
+      card_name_fix_flow_view_android, GetAccountHolderName(),
+      /*upload_save_card_callback=*/std::move(callback));
 }
 
 void ChromeAutofillClient::ConfirmExpirationDateFixFlow(
diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h
index c1efc46..9025d30 100644
--- a/chrome/browser/ui/autofill/chrome_autofill_client.h
+++ b/chrome/browser/ui/autofill/chrome_autofill_client.h
@@ -23,11 +23,13 @@
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_contents_user_data.h"
 
-#if !defined(OS_ANDROID)
+#if defined(OS_ANDROID)
+#include "components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.h"
+#else  // !OS_ANDROID
 #include "chrome/browser/ui/autofill/payments/manage_migration_ui_controller.h"
 #include "chrome/browser/ui/autofill/payments/save_card_bubble_controller.h"
 #include "components/zoom/zoom_observer.h"
-#endif  // !defined(OS_ANDROID)
+#endif
 
 namespace content {
 class WebContents;
@@ -166,6 +168,9 @@
   base::WeakPtr<AutofillPopupControllerImpl> popup_controller_;
   CardUnmaskPromptControllerImpl unmask_controller_;
   std::unique_ptr<LogManager> log_manager_;
+#if defined(OS_ANDROID)
+  CardNameFixFlowControllerImpl card_name_fix_flow_controller_;
+#endif
 
   WEB_CONTENTS_USER_DATA_KEY_DECL();
 
diff --git a/chrome/browser/ui/browser.cc b/chrome/browser/ui/browser.cc
index f8a1d1e..d0918502 100644
--- a/chrome/browser/ui/browser.cc
+++ b/chrome/browser/ui/browser.cc
@@ -87,6 +87,7 @@
 #include "chrome/browser/sessions/session_tab_helper.h"
 #include "chrome/browser/sessions/tab_restore_service_factory.h"
 #include "chrome/browser/ssl/security_state_tab_helper.h"
+#include "chrome/browser/subresource_filter/chrome_subresource_filter_client.h"
 #include "chrome/browser/tab_contents/tab_util.h"
 #include "chrome/browser/task_manager/web_contents_tags.h"
 #include "chrome/browser/themes/theme_service.h"
@@ -179,6 +180,7 @@
 #include "components/sessions/core/session_types.h"
 #include "components/sessions/core/tab_restore_service.h"
 #include "components/startup_metric_utils/browser/startup_metric_utils.h"
+#include "components/subresource_filter/content/browser/content_subresource_filter_throttle_manager.h"
 #include "components/translate/core/browser/language_state.h"
 #include "components/user_manager/user_manager.h"
 #include "components/viz/common/surfaces/surface_id.h"
@@ -1376,6 +1378,15 @@
 #endif  // defined(OS_CHROMEOS)
 }
 
+bool Browser::IsFrameLowPriority(
+    const content::WebContents* web_contents,
+    const content::RenderFrameHost* render_frame_host) {
+  const auto* client =
+      ChromeSubresourceFilterClient::FromWebContents(web_contents);
+  return client &&
+         client->GetThrottleManager()->IsFrameTaggedAsAd(render_frame_host);
+}
+
 bool Browser::IsMouseLocked() const {
   return exclusive_access_manager_->mouse_lock_controller()->IsMouseLocked();
 }
diff --git a/chrome/browser/ui/browser.h b/chrome/browser/ui/browser.h
index cac6e0a..a99f31d 100644
--- a/chrome/browser/ui/browser.h
+++ b/chrome/browser/ui/browser.h
@@ -582,6 +582,9 @@
       bool did_start_load,
       bool did_finish_load) override;
   bool ShouldShowStaleContentOnEviction(content::WebContents* source) override;
+  bool IsFrameLowPriority(
+      const content::WebContents* web_contents,
+      const content::RenderFrameHost* render_frame_host) override;
 
   bool is_type_normal() const { return type_ == TYPE_NORMAL; }
   bool is_type_popup() const { return type_ == TYPE_POPUP; }
diff --git a/chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer_unittest.cc b/chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer_unittest.cc
index b7f1571..47600d4d 100644
--- a/chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer_unittest.cc
+++ b/chrome/browser/ui/omnibox/chrome_omnibox_navigation_observer_unittest.cc
@@ -298,13 +298,14 @@
       net::RedirectInfo redir_info;
       redir_info.new_url = GURL(response.urls[dest]);
       redir_info.status_code = net::HTTP_MOVED_PERMANENTLY;
-      network::ResourceResponseHead redir_head =
-          network::CreateResourceResponseHead(net::HTTP_MOVED_PERMANENTLY);
-      redirects.push_back({redir_info, redir_head});
+      auto redir_head =
+          network::CreateURLResponseHead(net::HTTP_MOVED_PERMANENTLY);
+      redirects.push_back({redir_info, std::move(redir_head)});
     }
 
     // Fill in final response.
-    network::ResourceResponseHead http_head;
+    network::mojom::URLResponseHeadPtr http_head =
+        network::mojom::URLResponseHead::New();
     network::URLLoaderCompletionStatus net_status;
     network::TestURLLoaderFactory::ResponseProduceFlags response_flags =
         network::TestURLLoaderFactory::kResponseDefault;
@@ -316,13 +317,13 @@
       net_status = network::URLLoaderCompletionStatus(net::ERR_FAILED);
     } else {
       net_status = network::URLLoaderCompletionStatus(net::OK);
-      http_head = network::CreateResourceResponseHead(
-          static_cast<net::HttpStatusCode>(response.http_response_code));
+      http_head = std::move(network::CreateURLResponseHead(
+          static_cast<net::HttpStatusCode>(response.http_response_code)));
     }
 
-    test_url_loader_factory.AddResponse(GURL(response.urls[0]), http_head,
-                                        response.content, net_status,
-                                        redirects);
+    test_url_loader_factory.AddResponse(GURL(response.urls[0]),
+                                        std::move(http_head), response.content,
+                                        net_status, std::move(redirects));
 
     // Create the alternate nav match and the observer.
     // |observer| gets deleted automatically after all fetchers complete.
diff --git a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
index 4d4ba70..8c31a7b 100644
--- a/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
+++ b/chrome/browser/ui/omnibox/omnibox_view_browsertest.cc
@@ -1310,104 +1310,12 @@
 
 #if !defined(OS_MACOSX)
 // Mac intentionally does not support this behavior.
-IN_PROC_BROWSER_TEST_F(OmniboxViewTest, TabTraverseResultsTest) {
-  OmniboxView* omnibox_view = nullptr;
-  ASSERT_NO_FATAL_FAILURE(GetOmniboxView(&omnibox_view));
-  OmniboxPopupModel* popup_model = omnibox_view->model()->popup_model();
-  ASSERT_TRUE(popup_model);
-
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndDisableFeature(omnibox::kOmniboxWrapPopupPosition);
-
-  // Input something to trigger results.
-  const ui::KeyboardCode kKeys[] = {
-    ui::VKEY_B, ui::VKEY_A, ui::VKEY_R, ui::VKEY_UNKNOWN
-  };
-  ASSERT_NO_FATAL_FAILURE(SendKeySequence(kKeys));
-  ASSERT_NO_FATAL_FAILURE(WaitForAutocompleteControllerDone());
-  ASSERT_TRUE(popup_model->IsOpen());
-
-  size_t old_selected_line = popup_model->selected_line();
-  EXPECT_EQ(0U, old_selected_line);
-
-  // Move down the results.
-  for (size_t size = popup_model->result().size();
-       popup_model->selected_line() < size - 1;
-       old_selected_line = popup_model->selected_line()) {
-    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, 0));
-    ASSERT_FALSE(omnibox_view->model()->is_keyword_hint());
-    ASSERT_EQ(base::string16(), omnibox_view->model()->keyword());
-    ASSERT_LT(old_selected_line, popup_model->selected_line());
-  }
-
-  // Don't move past the end.
-  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, 0));
-  ASSERT_EQ(old_selected_line, popup_model->selected_line());
-  ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
-
-  // Move back up the results.
-  for (; popup_model->selected_line() > 0U;
-       old_selected_line = popup_model->selected_line()) {
-    ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, ui::EF_SHIFT_DOWN));
-    ASSERT_GT(old_selected_line, popup_model->selected_line());
-  }
-
-  // Don't move past the beginning.
-  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, ui::EF_SHIFT_DOWN));
-  ASSERT_EQ(0U, popup_model->selected_line());
-  ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
-
-  const TestHistoryEntry kHistoryFoo = {
-    "http://foo/", "Page foo", 1, 1, false
-  };
-
-  // Add a history entry so "foo" gets multiple matches.
-  ASSERT_NO_FATAL_FAILURE(AddHistoryEntry(
-      kHistoryFoo, base::Time::Now() - base::TimeDelta::FromHours(1)));
-
-  // Load results.
-  ASSERT_NO_FATAL_FAILURE(omnibox_view->SelectAll(false));
-  ASSERT_NO_FATAL_FAILURE(SendKeySequence(kSearchKeywordKeys));
-  ASSERT_NO_FATAL_FAILURE(WaitForAutocompleteControllerDone());
-
-  // Trigger keyword mode by tab.
-  base::string16 text = ASCIIToUTF16(kSearchKeyword);
-  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, 0));
-  ASSERT_FALSE(omnibox_view->model()->is_keyword_hint());
-  ASSERT_EQ(text, omnibox_view->model()->keyword());
-  ASSERT_TRUE(omnibox_view->GetText().empty());
-  ASSERT_EQ(0U, omnibox_view->model()->popup_model()->selected_line());
-
-  // The location bar should still have focus.
-  ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
-
-  // Pressing tab again should move to the next result and clear keyword
-  // mode.
-  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, 0));
-  ASSERT_FALSE(omnibox_view->model()->is_keyword_hint());
-  ASSERT_NE(text, omnibox_view->model()->keyword());
-  ASSERT_EQ(1U, omnibox_view->model()->popup_model()->selected_line());
-
-  // The location bar should still have focus.
-  ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
-
-  // Moving back up should not show keyword mode.
-  ASSERT_NO_FATAL_FAILURE(SendKey(ui::VKEY_TAB, ui::EF_SHIFT_DOWN));
-  ASSERT_TRUE(omnibox_view->model()->is_keyword_hint());
-  ASSERT_EQ(text, omnibox_view->model()->keyword());
-
-  ASSERT_TRUE(ui_test_utils::IsViewFocused(browser(), VIEW_ID_OMNIBOX));
-}
-
 IN_PROC_BROWSER_TEST_F(OmniboxViewTest, WrappingTabTraverseResultsTest) {
   OmniboxView* omnibox_view = nullptr;
   ASSERT_NO_FATAL_FAILURE(GetOmniboxView(&omnibox_view));
   OmniboxPopupModel* popup_model = omnibox_view->model()->popup_model();
   ASSERT_TRUE(popup_model);
 
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndEnableFeature(omnibox::kOmniboxWrapPopupPosition);
-
   // Input something to trigger results.
   const ui::KeyboardCode kKeys[] = {ui::VKEY_B, ui::VKEY_A, ui::VKEY_R,
                                     ui::VKEY_UNKNOWN};
diff --git a/chrome/browser/ui/page_info/page_info.cc b/chrome/browser/ui/page_info/page_info.cc
index 94018b0d5..fca4ffc 100644
--- a/chrome/browser/ui/page_info/page_info.cc
+++ b/chrome/browser/ui/page_info/page_info.cc
@@ -456,7 +456,7 @@
     return;
   }
 
-  if (security_level_ == security_state::HTTP_SHOW_WARNING) {
+  if (security_level_ == security_state::WARNING) {
     UMA_HISTOGRAM_ENUMERATION("Security.PageInfo.Action.HttpUrl.Warning",
                               action, PAGE_INFO_COUNT);
   } else if (security_level_ == security_state::DANGEROUS) {
diff --git a/chrome/browser/ui/page_info/page_info_unittest.cc b/chrome/browser/ui/page_info/page_info_unittest.cc
index 83e41492..e4854f2 100644
--- a/chrome/browser/ui/page_info/page_info_unittest.cc
+++ b/chrome/browser/ui/page_info/page_info_unittest.cc
@@ -996,7 +996,7 @@
        "Security.PageInfo.Action.HttpsUrl.Downgraded"},
       {"https://example.test", security_state::DANGEROUS,
        "Security.PageInfo.Action.HttpsUrl.Dangerous"},
-      {"http://example.test", security_state::HTTP_SHOW_WARNING,
+      {"http://example.test", security_state::WARNING,
        "Security.PageInfo.Action.HttpUrl.Warning"},
       {"http://example.test", security_state::DANGEROUS,
        "Security.PageInfo.Action.HttpUrl.Dangerous"},
diff --git a/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc
index 3a17c89..1111420 100644
--- a/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc
+++ b/chrome/browser/ui/startup/credential_provider_signin_info_fetcher_win_unittest.cc
@@ -110,17 +110,17 @@
     int token_info_net_error) {
   test_url_loader_factory_.AddResponse(
       GaiaUrls::GetInstance()->oauth2_token_info_url(),
-      network::CreateResourceResponseHead(token_info_code), token_info_data,
+      network::CreateURLResponseHead(token_info_code), token_info_data,
       network::URLLoaderCompletionStatus(token_info_net_error));
 
   test_url_loader_factory_.AddResponse(
       GaiaUrls::GetInstance()->oauth_user_info_url(),
-      network::CreateResourceResponseHead(user_info_code), user_info_data,
+      network::CreateURLResponseHead(user_info_code), user_info_data,
       network::URLLoaderCompletionStatus(user_info_net_error));
 
   test_url_loader_factory_.AddResponse(
       GaiaUrls::GetInstance()->oauth2_token_url(),
-      network::CreateResourceResponseHead(access_token_fetch_code),
+      network::CreateURLResponseHead(access_token_fetch_code),
       access_token_fetch_data,
       network::URLLoaderCompletionStatus(access_token_net_error));
 }
diff --git a/chrome/browser/ui/tabs/tab_strip_model.cc b/chrome/browser/ui/tabs/tab_strip_model.cc
index 4d2eec5..8a9840ed 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.cc
+++ b/chrome/browser/ui/tabs/tab_strip_model.cc
@@ -64,6 +64,23 @@
 
 class RenderWidgetHostVisibilityTracker;
 
+// Works similarly to base::AutoReset but checks for access from the wrong
+// thread as well as ensuring that the previous value of the re-entrancy guard
+// variable was false.
+class ReentrancyCheck {
+ public:
+  explicit ReentrancyCheck(bool* guard_flag) : guard_flag_(guard_flag) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
+    DCHECK(!*guard_flag_);
+    *guard_flag_ = true;
+  }
+
+  ~ReentrancyCheck() { *guard_flag_ = false; }
+
+ private:
+  bool* const guard_flag_;
+};
+
 // Returns true if the specified transition is one of the types that cause the
 // opener relationships for the tab in which the transition occurred to be
 // forgotten. This is generally any navigation that isn't a link click (i.e.
@@ -382,17 +399,14 @@
                                        std::unique_ptr<WebContents> contents,
                                        int add_types,
                                        base::Optional<TabGroupId> group) {
-  DCHECK(!reentrancy_guard_);
-  base::AutoReset<bool> resetter(&reentrancy_guard_, true);
-
+  ReentrancyCheck reentrancy_check(&reentrancy_guard_);
   return InsertWebContentsAtImpl(index, std::move(contents), add_types, group);
 }
 
 std::unique_ptr<content::WebContents> TabStripModel::ReplaceWebContentsAt(
     int index,
     std::unique_ptr<WebContents> new_contents) {
-  DCHECK(!reentrancy_guard_);
-  base::AutoReset<bool> resetter(&reentrancy_guard_, true);
+  ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
   delegate()->WillAddWebContents(new_contents.get());
 
@@ -426,8 +440,7 @@
 
 std::unique_ptr<content::WebContents> TabStripModel::DetachWebContentsAt(
     int index) {
-  DCHECK(!reentrancy_guard_);
-  base::AutoReset<bool> resetter(&reentrancy_guard_, true);
+  ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
   DCHECK_NE(active_index(), kNoTab) << "Activate the TabStripModel by "
                                        "selecting at least one tab before "
@@ -549,8 +562,7 @@
 }
 
 void TabStripModel::ActivateTabAt(int index, UserGestureDetails user_gesture) {
-  DCHECK(!reentrancy_guard_);
-  base::AutoReset<bool> resetter(&reentrancy_guard_, true);
+  ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
   DCHECK(ContainsIndex(index));
   TRACE_EVENT0("ui", "TabStripModel::ActivateTabAt");
@@ -613,8 +625,7 @@
 int TabStripModel::MoveWebContentsAt(int index,
                                      int to_position,
                                      bool select_after_move) {
-  DCHECK(!reentrancy_guard_);
-  base::AutoReset<bool> resetter(&reentrancy_guard_, true);
+  ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
   DCHECK(ContainsIndex(index));
 
@@ -634,8 +645,7 @@
 }
 
 void TabStripModel::MoveSelectedTabsTo(int index) {
-  DCHECK(!reentrancy_guard_);
-  base::AutoReset<bool> resetter(&reentrancy_guard_, true);
+  ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
   int total_pinned_count = IndexOfFirstNonPinnedTab();
   int selected_pinned_count = 0;
@@ -704,8 +714,7 @@
 }
 
 void TabStripModel::CloseAllTabs() {
-  DCHECK(!reentrancy_guard_);
-  base::AutoReset<bool> resetter(&reentrancy_guard_, true);
+  ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
   // Set state so that observers can adjust their behavior to suit this
   // specific condition when CloseWebContentsAt causes a flurry of
@@ -803,8 +812,7 @@
 }
 
 void TabStripModel::SetTabPinned(int index, bool pinned) {
-  DCHECK(!reentrancy_guard_);
-  base::AutoReset<bool> resetter(&reentrancy_guard_, true);
+  ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
   SetTabPinnedImpl(index, pinned);
 }
@@ -845,8 +853,7 @@
 
 void TabStripModel::SetVisualDataForGroup(TabGroupId group,
                                           TabGroupVisualData data) {
-  DCHECK(!reentrancy_guard_);
-  base::AutoReset<bool> resetter(&reentrancy_guard_, true);
+  ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
   DCHECK(base::Contains(group_data_, group));
   auto data_it = group_data_.find(group);
@@ -955,8 +962,7 @@
                                    ui::PageTransition transition,
                                    int add_types,
                                    base::Optional<TabGroupId> group) {
-  DCHECK(!reentrancy_guard_);
-  base::AutoReset<bool> resetter(&reentrancy_guard_, true);
+  ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
   // If the newly-opened tab is part of the same task as the parent tab, we want
   // to inherit the parent's opener attribute, so that if this tab is then
@@ -1038,8 +1044,7 @@
 }
 
 void TabStripModel::CloseSelectedTabs() {
-  DCHECK(!reentrancy_guard_);
-  base::AutoReset<bool> resetter(&reentrancy_guard_, true);
+  ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
   InternalCloseTabs(
       GetWebContentsesByIndices(selection_model_.selected_indices()),
@@ -1071,8 +1076,7 @@
 }
 
 TabGroupId TabStripModel::AddToNewGroup(const std::vector<int>& indices) {
-  DCHECK(!reentrancy_guard_);
-  base::AutoReset<bool> resetter(&reentrancy_guard_, true);
+  ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
   // The odds of |new_group| colliding with an existing group are astronomically
   // low. If there is a collision, a DCHECK will fail in |AddToNewGroupImpl()|,
@@ -1085,8 +1089,7 @@
 
 void TabStripModel::AddToExistingGroup(const std::vector<int>& indices,
                                        TabGroupId group) {
-  DCHECK(!reentrancy_guard_);
-  base::AutoReset<bool> resetter(&reentrancy_guard_, true);
+  ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
   AddToExistingGroupImpl(indices, group);
 }
@@ -1094,16 +1097,14 @@
 void TabStripModel::MoveTabsIntoGroup(const std::vector<int>& indices,
                                       int destination_index,
                                       TabGroupId group) {
-  DCHECK(!reentrancy_guard_);
-  base::AutoReset<bool> resetter(&reentrancy_guard_, true);
+  ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
   MoveTabsIntoGroupImpl(indices, destination_index, group);
 }
 
 void TabStripModel::AddToGroupForRestore(const std::vector<int>& indices,
                                          TabGroupId group) {
-  DCHECK(!reentrancy_guard_);
-  base::AutoReset<bool> resetter(&reentrancy_guard_, true);
+  ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
   const bool group_exists = base::Contains(group_data_, group);
   if (group_exists)
@@ -1116,8 +1117,7 @@
     int index,
     base::Optional<TabGroupId> group_id,
     base::Optional<TabGroupVisualData> group_data) {
-  DCHECK(!reentrancy_guard_);
-  base::AutoReset<bool> resetter(&reentrancy_guard_, true);
+  ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
   // Ungroup tab before moving, so that if this is the last tab in the group
   // observers can delete that group.
@@ -1151,8 +1151,7 @@
 }
 
 void TabStripModel::RemoveFromGroup(const std::vector<int>& indices) {
-  DCHECK(!reentrancy_guard_);
-  base::AutoReset<bool> resetter(&reentrancy_guard_, true);
+  ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
   // Remove each tab from the group it's in, if any. Go from right to left
   // since tabs may move to the right.
@@ -1294,8 +1293,7 @@
     }
 
     case CommandCloseTab: {
-      DCHECK(!reentrancy_guard_);
-      base::AutoReset<bool> resetter(&reentrancy_guard_, true);
+      ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
       base::RecordAction(UserMetricsAction("TabContextMenu_CloseTab"));
       InternalCloseTabs(
@@ -1305,8 +1303,7 @@
     }
 
     case CommandCloseTabsToRight: {
-      DCHECK(!reentrancy_guard_);
-      base::AutoReset<bool> resetter(&reentrancy_guard_, true);
+      ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
       base::RecordAction(UserMetricsAction("TabContextMenu_CloseTabsToRight"));
       InternalCloseTabs(GetWebContentsesByIndices(GetIndicesClosedByCommand(
@@ -1323,8 +1320,7 @@
     }
 
     case CommandTogglePinned: {
-      DCHECK(!reentrancy_guard_);
-      base::AutoReset<bool> resetter(&reentrancy_guard_, true);
+      ReentrancyCheck reentrancy_check(&reentrancy_guard_);
 
       base::RecordAction(UserMetricsAction("TabContextMenu_TogglePinned"));
       std::vector<int> indices = GetIndicesForCommand(context_index);
diff --git a/chrome/browser/ui/tabs/tab_strip_model.h b/chrome/browser/ui/tabs/tab_strip_model.h
index 162ce460..ef77f18 100644
--- a/chrome/browser/ui/tabs/tab_strip_model.h
+++ b/chrome/browser/ui/tabs/tab_strip_model.h
@@ -68,6 +68,9 @@
 // the View, and the Browser object likewise implements to be able to update
 // its bookkeeping when such events happen.
 //
+// This implementation of TabStripModel is not thread-safe and should only be
+// accessed on the UI thread.
+//
 ////////////////////////////////////////////////////////////////////////////////
 class TabStripModel {
  public:
diff --git a/chrome/browser/ui/test/browser_ui_browsertest.cc b/chrome/browser/ui/test/browser_ui_browsertest.cc
index dcea9ff..3e7d3c1 100644
--- a/chrome/browser/ui/test/browser_ui_browsertest.cc
+++ b/chrome/browser/ui/test/browser_ui_browsertest.cc
@@ -11,7 +11,6 @@
 #include "build/build_config.h"
 #include "content/public/common/content_switches.h"
 #include "testing/gtest/include/gtest/gtest.h"
-#include "ui/compositor/compositor_switches.h"
 
 namespace {
 
@@ -68,22 +67,13 @@
 
   base::LaunchOptions options;
 
-  // Generate screen output if --test-launcher-interactive was specified.
-  if (command.HasSwitch(switches::kTestLauncherInteractive)) {
-    command.AppendSwitch(switches::kEnablePixelOutputInTests);
 #if defined(OS_WIN)
-    // Under Windows, the child process won't launch without the wait option.
-    // See http://crbug.com/688534.
-    options.wait = true;
-    // Under Windows, dialogs (but not the browser window) created in the
-    // spawned browser_test process are invisible for some unknown reason.
-    // Pass in --disable-gpu to resolve this for now. See
-    // http://crbug.com/687387.
-    command.AppendSwitch(switches::kDisableGpu);
+  // Under Windows, the child process won't launch without the wait option.
+  // See http://crbug.com/688534.
+  options.wait = true;
+#else
+  options.wait = !command.HasSwitch(switches::kTestLauncherInteractive);
 #endif
-  } else {
-    options.wait = true;
-  }
 
   base::LaunchProcess(command, options);
 }
diff --git a/chrome/browser/ui/views/autofill/payments/local_card_migration_icon_view.cc b/chrome/browser/ui/views/autofill/payments/local_card_migration_icon_view.cc
index c2fcfb4..9fc4090 100644
--- a/chrome/browser/ui/views/autofill/payments/local_card_migration_icon_view.cc
+++ b/chrome/browser/ui/views/autofill/payments/local_card_migration_icon_view.cc
@@ -70,11 +70,11 @@
       // credit card icon.
       case LocalCardMigrationFlowStep::OFFER_DIALOG: {
         UpdateIconImage();
-        AnimateInkDrop(views::InkDropState::ACTIVATED, /*event=*/nullptr);
+        SetHighlighted(true);
         break;
       }
       case LocalCardMigrationFlowStep::MIGRATION_RESULT_PENDING: {
-        AnimateInkDrop(views::InkDropState::HIDDEN, /*event=*/nullptr);
+        SetHighlighted(false);
         // Disable the credit card icon so it does not update if user clicks
         // on it.
         SetEnabled(false);
@@ -95,6 +95,7 @@
         break;
     }
   } else {
+    SetHighlighted(false);
     // Handle corner cases where users navigate away or close the tab.
     UnpauseAnimation();
   }
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index b67c4cfd..4768bb8 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -876,7 +876,7 @@
   infobar_container_->ChangeInfoBarManager(
       InfoBarService::FromWebContents(new_contents));
 
-  ObserveAppBannerManager(
+  OnAppBannerManagerChanged(
       banners::AppBannerManager::FromWebContents(new_contents));
 
   UpdateUIForContents(new_contents);
@@ -933,7 +933,7 @@
     web_contents_close_handler_->ActiveTabChanged();
     contents_web_view_->SetWebContents(nullptr);
     infobar_container_->ChangeInfoBarManager(nullptr);
-    ObserveAppBannerManager(nullptr);
+    app_banner_manager_observer_.RemoveAll();
     UpdateDevToolsForContents(nullptr, true);
   }
 }
@@ -3250,6 +3250,12 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 // BrowserView, banners::AppBannerManager::Observer implementation:
+void BrowserView::OnAppBannerManagerChanged(
+    banners::AppBannerManager* new_manager) {
+  app_banner_manager_observer_.RemoveAll();
+  app_banner_manager_observer_.Add(new_manager);
+}
+
 void BrowserView::OnInstallableWebAppStatusUpdated() {
   UpdatePageActionIcon(PageActionIconType::kPwaInstall);
 }
diff --git a/chrome/browser/ui/views/frame/browser_view.h b/chrome/browser/ui/views/frame/browser_view.h
index 7490826..6da1c30 100644
--- a/chrome/browser/ui/views/frame/browser_view.h
+++ b/chrome/browser/ui/views/frame/browser_view.h
@@ -540,6 +540,8 @@
   void OnImmersiveModeControllerDestroyed() override;
 
   // banners::AppBannerManager::Observer:
+  void OnAppBannerManagerChanged(
+      banners::AppBannerManager* new_manager) override;
   void OnInstallableWebAppStatusUpdated() override;
 
   // Creates an accessible tab label for screen readers that includes the tab
@@ -846,6 +848,9 @@
 
   ReopenTabPromoController reopen_tab_promo_controller_{this};
 
+  ScopedObserver<banners::AppBannerManager, banners::AppBannerManager::Observer>
+      app_banner_manager_observer_{this};
+
   struct ResizeSession {
     // The time when user started resizing the window.
     base::TimeTicks begin_timestamp;
diff --git a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc
index f72a0a5..6560573 100644
--- a/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc
+++ b/chrome/browser/ui/views/frame/top_controls_slide_controller_chromeos.cc
@@ -77,7 +77,7 @@
 
   auto* helper = SecurityStateTabHelper::FromWebContents(contents);
   switch (helper->GetSecurityLevel()) {
-    case security_state::HTTP_SHOW_WARNING:
+    case security_state::WARNING:
     case security_state::DANGEROUS:
       return content::BROWSER_CONTROLS_STATE_SHOWN;
 
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
index 9423376..24dd1d6 100644
--- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
+++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.cc
@@ -22,6 +22,8 @@
 #include "ui/gfx/scoped_canvas.h"
 #include "ui/gfx/skia_util.h"
 #include "ui/native_theme/native_theme.h"
+#include "ui/views/accessibility/ax_virtual_view.h"
+#include "ui/views/accessibility/view_accessibility.h"
 #include "ui/views/animation/flood_fill_ink_drop_ripple.h"
 #include "ui/views/animation/ink_drop_highlight.h"
 #include "ui/views/animation/ink_drop_impl.h"
@@ -141,6 +143,11 @@
   // Flip the canvas in RTL so the separator is drawn on the correct side.
   separator_view_->EnableCanvasFlippingForRTLUI(true);
 
+  auto alert_view = std::make_unique<views::AXVirtualView>();
+  alert_view->GetCustomData().role = ax::mojom::Role::kAlert;
+  alert_virtual_view_ = alert_view.get();
+  GetViewAccessibility().AddVirtualChildView(std::move(alert_view));
+
   md_observer_.Add(MD::GetInstance());
 }
 
@@ -430,8 +437,18 @@
     // Start animation from the current width, otherwise the icon will also be
     // included if visible.
     grow_animation_starting_width_ = width();
-    if (string_id)
-      SetLabel(l10n_util::GetStringUTF16(string_id.value()));
+    if (string_id) {
+      base::string16 label = l10n_util::GetStringUTF16(string_id.value());
+      SetLabel(label);
+
+      // Send an accessibility alert whose text is the label's text. Doing this
+      // causes a screenreader to immediately announce the text of the button,
+      // which serves to announce it. This is done unconditionally here if there
+      // is text because the animation is intended to draw attention to the
+      // instance anyway.
+      alert_virtual_view_->GetCustomData().SetName(label);
+      alert_virtual_view_->NotifyAccessibilityEvent(ax::mojom::Event::kAlert);
+    }
     label()->SetVisible(true);
     ShowAnimation();
   }
diff --git a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
index 3acd5e1..d99cba0 100644
--- a/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
+++ b/chrome/browser/ui/views/location_bar/icon_label_bubble_view.h
@@ -32,6 +32,7 @@
 }
 
 namespace views {
+class AXVirtualView;
 class ImageView;
 }
 
@@ -246,6 +247,10 @@
   // icon). Set before animation begins in AnimateIn().
   int grow_animation_starting_width_ = 0;
 
+  // Virtual view, used for announcing changes to the state of this view. A
+  // virtual child of this view.
+  views::AXVirtualView* alert_virtual_view_;
+
   ScopedObserver<ui::MaterialDesignController,
                  ui::MaterialDesignControllerObserver>
       md_observer_{this};
diff --git a/chrome/browser/ui/views/location_bar/location_icon_view.cc b/chrome/browser/ui/views/location_bar/location_icon_view.cc
index dd120cf..8b298aa0 100644
--- a/chrome/browser/ui/views/location_bar/location_icon_view.cc
+++ b/chrome/browser/ui/views/location_bar/location_icon_view.cc
@@ -170,13 +170,12 @@
     return false;
 
   SecurityLevel level = delegate_->GetLocationBarModel()->GetSecurityLevel();
-  // Do not animate transitions from HTTP_SHOW_WARNING to DANGEROUS, since the
-  // transition can look confusing/messy.
+  // Do not animate transitions from WARNING to DANGEROUS, since
+  // the transition can look confusing/messy.
   if (level == SecurityLevel::DANGEROUS &&
-      last_update_security_level_ == SecurityLevel::HTTP_SHOW_WARNING)
+      last_update_security_level_ == SecurityLevel::WARNING)
     return false;
-  return (level == SecurityLevel::DANGEROUS ||
-          level == SecurityLevel::HTTP_SHOW_WARNING);
+  return (level == SecurityLevel::DANGEROUS || level == SecurityLevel::WARNING);
 }
 
 void LocationIconView::UpdateTextVisibility(bool suppress_animations) {
diff --git a/chrome/browser/ui/views/location_bar/location_icon_view_unittest.cc b/chrome/browser/ui/views/location_bar/location_icon_view_unittest.cc
index 29347ed..83c91c6 100644
--- a/chrome/browser/ui/views/location_bar/location_icon_view_unittest.cc
+++ b/chrome/browser/ui/views/location_bar/location_icon_view_unittest.cc
@@ -87,7 +87,7 @@
 
     base::string16 secure_display_text = base::string16();
     if (level == security_state::SecurityLevel::DANGEROUS ||
-        level == security_state::SecurityLevel::HTTP_SHOW_WARNING)
+        level == security_state::SecurityLevel::WARNING)
       secure_display_text = base::ASCIIToUTF16("Insecure");
 
     location_bar_model()->set_secure_display_text(secure_display_text);
@@ -129,7 +129,7 @@
   SetSecurityLevel(security_state::SecurityLevel::SECURE);
   view()->Update(/*suppress_animations=*/true);
 
-  SetSecurityLevel(security_state::SecurityLevel::HTTP_SHOW_WARNING);
+  SetSecurityLevel(security_state::SecurityLevel::WARNING);
   view()->Update(/*suppress_animations=*/false);
   EXPECT_TRUE(view()->is_animating_label());
 }
@@ -146,7 +146,7 @@
 
 TEST_F(LocationIconViewTest, ShouldNotAnimateWarningToDangerous) {
   // Make sure the initial status is secure.
-  SetSecurityLevel(security_state::SecurityLevel::HTTP_SHOW_WARNING);
+  SetSecurityLevel(security_state::SecurityLevel::WARNING);
   view()->Update(/*suppress_animations=*/true);
 
   SetSecurityLevel(security_state::SecurityLevel::DANGEROUS);
diff --git a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
index 61fe4ec6..5af54a4 100644
--- a/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
+++ b/chrome/browser/ui/views/omnibox/omnibox_view_views.cc
@@ -1014,10 +1014,10 @@
 
   // Only SECURE and DANGEROUS levels (pages served over HTTPS or flagged by
   // SafeBrowsing) get a special scheme color treatment. If the security level
-  // is NONE or HTTP_SHOW_WARNING, we do not override the text style previously
-  // applied to the scheme text range by SetEmphasis().
+  // is NONE or WARNING, we do not override the text style
+  // previously applied to the scheme text range by SetEmphasis().
   if (security_level == security_state::NONE ||
-      security_level == security_state::HTTP_SHOW_WARNING)
+      security_level == security_state::WARNING)
     return;
   ApplyColor(location_bar_view_->GetSecurityChipColor(security_level), range);
   if (security_level == security_state::DANGEROUS)
diff --git a/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc b/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
index ab93e85..6c66338e 100644
--- a/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
+++ b/chrome/browser/ui/views/toolbar/browser_app_menu_button.cc
@@ -299,6 +299,13 @@
   PreferredSizeChanged();
 }
 
+void BrowserAppMenuButton::OnBoundsChanged(const gfx::Rect& previous_bounds) {
+  // AppMenuButton overrides parts of the ToolbarButton behavior.
+  // BrowserAppMenuButton is hosted on the toolbar so we need to make sure that
+  // ToolbarButton backgrounds etc. are properly updated.
+  ToolbarButton::OnBoundsChanged(previous_bounds);
+}
+
 const char* BrowserAppMenuButton::GetClassName() const {
   return "BrowserAppMenuButton";
 }
diff --git a/chrome/browser/ui/views/toolbar/browser_app_menu_button.h b/chrome/browser/ui/views/toolbar/browser_app_menu_button.h
index e7eee46..945b015 100644
--- a/chrome/browser/ui/views/toolbar/browser_app_menu_button.h
+++ b/chrome/browser/ui/views/toolbar/browser_app_menu_button.h
@@ -73,6 +73,7 @@
   base::Optional<SkColor> GetPromoHighlightColor() const;
 
   // AppMenuButton:
+  void OnBoundsChanged(const gfx::Rect& previous_bounds) override;
   const char* GetClassName() const override;
   bool GetDropFormats(int* formats,
                       std::set<ui::ClipboardFormatType>* format_types) override;
diff --git a/chrome/browser/ui/web_applications/web_app_launch_utils.cc b/chrome/browser/ui/web_applications/web_app_launch_utils.cc
index ae616ea..e608fb8d 100644
--- a/chrome/browser/ui/web_applications/web_app_launch_utils.cc
+++ b/chrome/browser/ui/web_applications/web_app_launch_utils.cc
@@ -49,7 +49,7 @@
       NOTREACHED();
       FALLTHROUGH;
     case security_state::NONE:
-    case security_state::HTTP_SHOW_WARNING:
+    case security_state::WARNING:
     case security_state::DANGEROUS:
       return base::nullopt;
     case security_state::EV_SECURE:
diff --git a/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_handler.cc b/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_handler.cc
index 5eccb3f..b88be86 100644
--- a/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_handler.cc
+++ b/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_handler.cc
@@ -43,6 +43,8 @@
   bool initial_toggle_value = false;
 
 #if defined(OS_CHROMEOS)
+  using chromeos::bluetooth::DebugLogsManager;
+
   // If no logs manager exists for this user, debug logs are not supported.
   DebugLogsManager::DebugLogsState state =
       debug_logs_manager_ ? debug_logs_manager_->GetDebugLogsState()
diff --git a/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_handler.h b/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_handler.h
index 54adcf05..5c1cd35 100644
--- a/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_handler.h
+++ b/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_handler.h
@@ -13,7 +13,11 @@
 #include "mojo/public/cpp/bindings/receiver.h"
 
 #if defined(OS_CHROMEOS)
+namespace chromeos {
+namespace bluetooth {
 class DebugLogsManager;
+}  // namespace bluetooth
+}  // namespace chromeos
 #endif
 
 // Handles API requests from chrome://bluetooth-internals page by implementing
@@ -25,7 +29,8 @@
   ~BluetoothInternalsHandler() override;
 
 #if defined(OS_CHROMEOS)
-  void set_debug_logs_manager(DebugLogsManager* debug_logs_manager) {
+  void set_debug_logs_manager(
+      chromeos::bluetooth::DebugLogsManager* debug_logs_manager) {
     debug_logs_manager_ = debug_logs_manager;
   }
 #endif
@@ -42,7 +47,7 @@
   mojo::Receiver<mojom::BluetoothInternalsHandler> receiver_;
 
 #if defined(OS_CHROMEOS)
-  DebugLogsManager* debug_logs_manager_ = nullptr;
+  chromeos::bluetooth::DebugLogsManager* debug_logs_manager_ = nullptr;
 #endif
 
   base::WeakPtrFactory<BluetoothInternalsHandler> weak_ptr_factory_{this};
diff --git a/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_ui.cc b/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_ui.cc
index e1e7674..6f8ab24 100644
--- a/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_ui.cc
+++ b/chrome/browser/ui/webui/bluetooth_internals/bluetooth_internals_ui.cc
@@ -52,6 +52,7 @@
       std::make_unique<BluetoothInternalsHandler>(std::move(receiver));
 #if defined(OS_CHROMEOS)
   page_handler_->set_debug_logs_manager(
-      DebugLogsManagerFactory::GetForProfile(Profile::FromWebUI(web_ui())));
+      chromeos::bluetooth::DebugLogsManagerFactory::GetForProfile(
+          Profile::FromWebUI(web_ui())));
 #endif
 }
diff --git a/chrome/browser/util/android/BUILD.gn b/chrome/browser/util/android/BUILD.gn
index 306aa5f6..8c5b7c5 100644
--- a/chrome/browser/util/android/BUILD.gn
+++ b/chrome/browser/util/android/BUILD.gn
@@ -6,6 +6,7 @@
 
 android_library("java") {
   java_files = [
+    "java/src/org/chromium/chrome/browser/util/AccessibilityUtil.java",
     "java/src/org/chromium/chrome/browser/util/AndroidTaskUtils.java",
     "java/src/org/chromium/chrome/browser/util/BitmapCache.java",
     "java/src/org/chromium/chrome/browser/util/ChromeContextUtil.java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/util/AccessibilityUtil.java b/chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/AccessibilityUtil.java
similarity index 98%
rename from chrome/android/java/src/org/chromium/chrome/browser/util/AccessibilityUtil.java
rename to chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/AccessibilityUtil.java
index b457e3ee..930bade 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/util/AccessibilityUtil.java
+++ b/chrome/browser/util/android/java/src/org/chromium/chrome/browser/util/AccessibilityUtil.java
@@ -25,7 +25,7 @@
     private static Boolean sIsAccessibilityEnabled;
     private static ActivityStateListener sActivityStateListener;
 
-    private AccessibilityUtil() { }
+    private AccessibilityUtil() {}
 
     /**
      * Checks to see that this device has accessibility and touch exploration enabled.
diff --git a/chrome/browser/vr/testapp/vr_test_context.cc b/chrome/browser/vr/testapp/vr_test_context.cc
index 077282a..6d5bc1d 100644
--- a/chrome/browser/vr/testapp/vr_test_context.cc
+++ b/chrome/browser/vr/testapp/vr_test_context.cc
@@ -569,7 +569,7 @@
 }
 
 void VrTestContext::Navigate(GURL gurl, NavigationMethod method) {
-  LocationBarState state(gurl, security_state::SecurityLevel::HTTP_SHOW_WARNING,
+  LocationBarState state(gurl, security_state::SecurityLevel::WARNING,
                          &omnibox::kHttpIcon, true, false);
   ui_->GetBrowserUiWeakPtr()->SetLocationBarState(state);
   page_load_start_ = base::TimeTicks::Now();
@@ -714,9 +714,8 @@
 
 void VrTestContext::CycleOrigin() {
   const std::vector<LocationBarState> states = {
-      {GURL("http://domain.com"),
-       security_state::SecurityLevel::HTTP_SHOW_WARNING, &omnibox::kHttpIcon,
-       true, false},
+      {GURL("http://domain.com"), security_state::SecurityLevel::WARNING,
+       &omnibox::kHttpIcon, true, false},
       {GURL("https://www.domain.com/path/segment/directory/file.html"),
        security_state::SecurityLevel::SECURE, &omnibox::kHttpsValidIcon, true,
        false},
@@ -724,47 +723,45 @@
        security_state::SecurityLevel::DANGEROUS, &omnibox::kHttpsInvalidIcon,
        true, false},
       // Do not show URL
-      {GURL(), security_state::SecurityLevel::HTTP_SHOW_WARNING,
-       &omnibox::kHttpIcon, false, false},
+      {GURL(), security_state::SecurityLevel::WARNING, &omnibox::kHttpIcon,
+       false, false},
       {GURL(), security_state::SecurityLevel::SECURE, &omnibox::kHttpsValidIcon,
        true, false},
       {GURL("file://very-very-very-long-file-hostname/path/path/path/path"),
-       security_state::SecurityLevel::HTTP_SHOW_WARNING, &omnibox::kHttpIcon,
-       true, false},
+       security_state::SecurityLevel::WARNING, &omnibox::kHttpIcon, true,
+       false},
       {GURL("file:///path/path/path/path/path/path/path/path/path"),
-       security_state::SecurityLevel::HTTP_SHOW_WARNING, &omnibox::kHttpIcon,
-       true, false},
+       security_state::SecurityLevel::WARNING, &omnibox::kHttpIcon, true,
+       false},
       // Elision-related cases.
       {GURL("http://domaaaaaaaaaaain.com"),
-       security_state::SecurityLevel::HTTP_SHOW_WARNING, &omnibox::kHttpIcon,
-       true, false},
+       security_state::SecurityLevel::WARNING, &omnibox::kHttpIcon, true,
+       false},
       {GURL("http://domaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaain.com"),
-       security_state::SecurityLevel::HTTP_SHOW_WARNING, &omnibox::kHttpIcon,
-       true, false},
-      {GURL("http://domain.com/a/"),
-       security_state::SecurityLevel::HTTP_SHOW_WARNING, &omnibox::kHttpIcon,
-       true, false},
+       security_state::SecurityLevel::WARNING, &omnibox::kHttpIcon, true,
+       false},
+      {GURL("http://domain.com/a/"), security_state::SecurityLevel::WARNING,
+       &omnibox::kHttpIcon, true, false},
       {GURL("http://domain.com/aaaaaaa/"),
-       security_state::SecurityLevel::HTTP_SHOW_WARNING, &omnibox::kHttpIcon,
-       true, false},
+       security_state::SecurityLevel::WARNING, &omnibox::kHttpIcon, true,
+       false},
       {GURL("http://domain.com/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/"),
-       security_state::SecurityLevel::HTTP_SHOW_WARNING, &omnibox::kHttpIcon,
-       true, false},
+       security_state::SecurityLevel::WARNING, &omnibox::kHttpIcon, true,
+       false},
       {GURL("http://domaaaaaaaaaaaaaaaaain.com/aaaaaaaaaaaaaaaaaaaaaaaaaaaaa/"),
-       security_state::SecurityLevel::HTTP_SHOW_WARNING, &omnibox::kHttpIcon,
-       true, false},
+       security_state::SecurityLevel::WARNING, &omnibox::kHttpIcon, true,
+       false},
       {GURL("http://domaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaain.com/aaaaaaaaaa/"),
-       security_state::SecurityLevel::HTTP_SHOW_WARNING, &omnibox::kHttpIcon,
-       true, false},
+       security_state::SecurityLevel::WARNING, &omnibox::kHttpIcon, true,
+       false},
       {GURL("http://www.domain.com/path/segment/directory/file.html"),
-       security_state::SecurityLevel::HTTP_SHOW_WARNING, &omnibox::kHttpIcon,
-       true, false},
+       security_state::SecurityLevel::WARNING, &omnibox::kHttpIcon, true,
+       false},
       {GURL("http://subdomain.domain.com/"),
-       security_state::SecurityLevel::HTTP_SHOW_WARNING, &omnibox::kHttpIcon,
-       true, false},
-      {GURL("http://中央大学.ಠ_ಠ.tw/"),
-       security_state::SecurityLevel::HTTP_SHOW_WARNING, &omnibox::kHttpIcon,
-       true, false},
+       security_state::SecurityLevel::WARNING, &omnibox::kHttpIcon, true,
+       false},
+      {GURL("http://中央大学.ಠ_ಠ.tw/"), security_state::SecurityLevel::WARNING,
+       &omnibox::kHttpIcon, true, false},
   };
 
   static int state = 0;
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index ab6018a..2951f8c9 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -1774,6 +1774,11 @@
 // launches.
 const char kRegisteredBackgroundContents[] = "background_contents.registered";
 
+// Integer that specifies the total memory usage, in mb, that chrome will
+// attempt to stay under. Can be specified via policy in addition to the default
+// memory pressure rules applied per platform.
+const char kTotalMemoryLimitMb[] = "total_memory_limit_mb";
+
 // String that lists supported HTTP authentication schemes.
 const char kAuthSchemes[] = "auth.schemes";
 
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index 1fa644a..cfab740 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -704,6 +704,8 @@
 
 extern const char kRegisteredBackgroundContents[];
 
+extern const char kTotalMemoryLimitMb[];
+
 extern const char kAuthSchemes[];
 extern const char kDisableAuthNegotiateCnameLookup[];
 extern const char kEnableAuthNegotiatePort[];
diff --git a/chrome/service/cloud_print/cloud_print_message_handler.cc b/chrome/service/cloud_print/cloud_print_message_handler.cc
index c1c6977..443a7c4b 100644
--- a/chrome/service/cloud_print/cloud_print_message_handler.cc
+++ b/chrome/service/cloud_print/cloud_print_message_handler.cc
@@ -4,10 +4,12 @@
 
 #include "chrome/service/cloud_print/cloud_print_message_handler.h"
 
+#include <memory>
+#include <utility>
 #include <vector>
 
 #include "chrome/common/cloud_print/cloud_print_proxy_info.h"
-#include "mojo/public/cpp/bindings/strong_binding.h"
+#include "mojo/public/cpp/bindings/self_owned_receiver.h"
 
 namespace cloud_print {
 
@@ -22,10 +24,10 @@
 // static
 void CloudPrintMessageHandler::Create(
     CloudPrintProxy::Provider* proxy_provider,
-    cloud_print::mojom::CloudPrintRequest request) {
-  mojo::MakeStrongBinding(
+    mojo::PendingReceiver<cloud_print::mojom::CloudPrint> receiver) {
+  mojo::MakeSelfOwnedReceiver(
       std::make_unique<CloudPrintMessageHandler>(proxy_provider),
-      std::move(request));
+      std::move(receiver));
 }
 
 void CloudPrintMessageHandler::EnableCloudPrintProxyWithRobot(
diff --git a/chrome/service/cloud_print/cloud_print_message_handler.h b/chrome/service/cloud_print/cloud_print_message_handler.h
index 6a46675..77160c0 100644
--- a/chrome/service/cloud_print/cloud_print_message_handler.h
+++ b/chrome/service/cloud_print/cloud_print_message_handler.h
@@ -10,6 +10,7 @@
 #include "base/macros.h"
 #include "chrome/common/cloud_print.mojom.h"
 #include "chrome/service/cloud_print/cloud_print_proxy.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
 
 namespace cloud_print {
 
@@ -19,8 +20,9 @@
   explicit CloudPrintMessageHandler(CloudPrintProxy::Provider* proxy_provider);
   ~CloudPrintMessageHandler() override;
 
-  static void Create(CloudPrintProxy::Provider* proxy_provider,
-                     cloud_print::mojom::CloudPrintRequest request);
+  static void Create(
+      CloudPrintProxy::Provider* proxy_provider,
+      mojo::PendingReceiver<cloud_print::mojom::CloudPrint> receiver);
 
  private:
   // cloud_print::mojom::CloudPrintProxy.
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index 710ceff5..d7e3b0d 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -5204,11 +5204,6 @@
   if (enable_openscreen) {
     include_dirs = [ "//third_party/openscreen/src" ]
 
-    deps += [
-      "//third_party/openscreen/src/platform:platform_unittests",
-      "//third_party/openscreen/src/platform:test",
-    ]
-
     sources += [
       "../browser/media/router/providers/openscreen/discovery/open_screen_listener_unittest.cc",
       "../browser/media/router/providers/openscreen/network_service_quic_packet_writer_unittest.cc",
diff --git a/chrome/test/base/browser_tests_main.cc b/chrome/test/base/browser_tests_main.cc
index c271eef..e7148af 100644
--- a/chrome/test/base/browser_tests_main.cc
+++ b/chrome/test/base/browser_tests_main.cc
@@ -4,12 +4,14 @@
 
 #include "base/command_line.h"
 #include "base/test/launcher/test_launcher.h"
+#include "base/test/test_switches.h"
 #include "build/build_config.h"
 #include "chrome/test/base/chrome_test_launcher.h"
 #include "chrome/test/base/chrome_test_suite.h"
+#include "content/public/common/content_switches.h"
+#include "ui/compositor/compositor_switches.h"
 
 #if defined(OS_WIN)
-#include "base/test/test_switches.h"
 #include "base/win/win_util.h"
 #endif  // defined(OS_WIN)
 
@@ -29,14 +31,25 @@
   // load and pin the module early on in startup before the blocking becomes an
   // issue.
   base::win::PinUser32();
+#endif  // defined(OS_WIN)
 
   // Enable high-DPI for interactive tests where the user is expected to
   // manually verify results.
-  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
-          switches::kTestLauncherInteractive)) {
+  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+  if (command_line->HasSwitch(switches::kTestLauncherInteractive)) {
+    // Since the test is interactive, the invoker will want to have pixel output
+    // to actually see the result.
+    command_line->AppendSwitch(switches::kEnablePixelOutputInTests);
+#if defined(OS_WIN)
+    // Under Windows, dialogs (but not the browser window) created in the
+    // spawned browser_test process are invisible for some unknown reason.
+    // Pass in --disable-gpu to resolve this for now. See
+    // http://crbug.com/687387.
+    command_line->AppendSwitch(switches::kDisableGpu);
+
     base::win::EnableHighDPISupport();
-  }
 #endif  // defined(OS_WIN)
+  }
 
   ChromeTestSuiteRunner runner;
   ChromeTestLauncherDelegate delegate(&runner);
diff --git a/chrome/test/data/policy/policy_test_cases.json b/chrome/test/data/policy/policy_test_cases.json
index a61de386..71319b5 100644
--- a/chrome/test/data/policy/policy_test_cases.json
+++ b/chrome/test/data/policy/policy_test_cases.json
@@ -5200,5 +5200,16 @@
     "pref_mappings": [
       { "pref": "hsts.policy.upgrade_bypass_list", "local_state": true }
     ]
+  },
+
+  "TotalMemoryLimitMb": {
+    "os": ["win", "mac"],
+    "test_policy": { "TotalMemoryLimitMb": 2048 },
+    "pref_mappings": [
+      {
+        "pref": "total_memory_limit_mb",
+        "local_state":  true
+      }
+    ]
   }
 }
diff --git a/chrome/test/data/webui/print_preview/custom_margins_test.js b/chrome/test/data/webui/print_preview/custom_margins_test.js
index a4275d4..3e62355 100644
--- a/chrome/test/data/webui/print_preview/custom_margins_test.js
+++ b/chrome/test/data/webui/print_preview/custom_margins_test.js
@@ -9,6 +9,7 @@
     SetFromStickySettings: 'set from sticky settings',
     DragControls: 'drag controls',
     SetControlsWithTextbox: 'set controls with textbox',
+    SetControlsWithTextboxMetric: 'set controls with textbox metric',
     RestoreStickyMarginsAfterDefault: 'restore sticky margins after default',
     MediaSizeClearsCustomMargins: 'media size clears custom margins',
     LayoutClearsCustomMargins: 'layout clears custom margins',
@@ -30,6 +31,9 @@
     /** @type {!Array<!print_preview.ticket_items.CustomMarginsOrientation>} */
     let sides = [];
 
+    /** @type {!print_preview.MeasurementSystem} */
+    let measurementSystem = null;
+
     /** @type {number} */
     const pixelsPerInch = 100;
 
@@ -45,6 +49,8 @@
     /** @override */
     setup(function() {
       PolymerTest.clearBody();
+      measurementSystem = new print_preview.MeasurementSystem(
+          ',', '.', print_preview.MeasurementSystemUnitType.IMPERIAL);
       model = document.createElement('print-preview-model');
       document.body.appendChild(model);
       model.set('settings.mediaSize.available', true);
@@ -64,8 +70,6 @@
       container.documentMargins = new print_preview.Margins(
           defaultMarginPts, defaultMarginPts, defaultMarginPts,
           defaultMarginPts);
-      container.measurementSystem = new print_preview.MeasurementSystem(
-          ',', '.', print_preview.MeasurementSystemUnitType.IMPERIAL);
       container.state = print_preview.State.NOT_READY;
     });
 
@@ -83,6 +87,7 @@
      */
     function finishSetup() {
       // Wait for the control elements to be created before updating the state.
+      container.measurementSystem = measurementSystem;
       document.body.appendChild(container);
       let controlsAdded = test_util.eventToPromise('dom-change', container);
       return controlsAdded.then(() => {
@@ -164,7 +169,8 @@
      * @param {string} input The new textbox input for the margin.
      * @param {boolean} invalid Whether the new value is invalid.
      * @param {number=} newValuePts the new margin value in pts. If not
-     *     specified, computes the value assuming it is in bounds.
+     *     specified, computes the value assuming it is in bounds and assuming
+     *     the default measurement system.
      * @return {!Promise} Promise that resolves when the test is complete.
      */
     function testControlTextbox(
@@ -399,38 +405,45 @@
       });
     });
 
+    /**
+     * @param {!Array<!MarginControlElement>} controls
+     * @param {number} currentValue Current margin value in pts
+     * @param {string} input String to set in margin textboxes
+     * @param {boolean} invalid Whether the string is invalid
+     * @param {number=} newValuePts the new margin value in pts. If not
+     *     specified, computes the value assuming it is in bounds and assuming
+     *     the default measurement system.
+     * @return {!Promise} Promise that resolves when all controls have been
+     *     tested.
+     */
+    function testAllTextboxes(
+        controls, currentValue, input, invalid, newValuePts) {
+      return testControlTextbox(
+                 controls[0], keys[0], currentValue, input, invalid,
+                 newValuePts)
+          .then(
+              () => testControlTextbox(
+                  controls[1], keys[1], currentValue, input, invalid,
+                  newValuePts))
+          .then(
+              () => testControlTextbox(
+                  controls[2], keys[2], currentValue, input, invalid,
+                  newValuePts))
+          .then(
+              () => testControlTextbox(
+                  controls[3], keys[3], currentValue, input, invalid,
+                  newValuePts));
+    }
+
     // Test that setting the margin controls with their textbox inputs updates
     // the custom margins setting.
     test(assert(TestNames.SetControlsWithTextbox), function() {
-      /**
-       * @param {!Array<!MarginControlElement>} controls
-       * @param {number} currentValue Current margin value in pts
-       * @param {string} input String to set in margin textboxes
-       * @param {boolean} invalid Whether the string is invalid
-       * @return {!Promise} Promise that resolves when all controls have been
-       *     tested.
-       */
-      const testAllTextboxes = function(
-          controls, currentValue, input, invalid) {
-        return testControlTextbox(
-                   controls[0], keys[0], currentValue, input, invalid)
-            .then(
-                () => testControlTextbox(
-                    controls[1], keys[1], currentValue, input, invalid))
-            .then(
-                () => testControlTextbox(
-                    controls[2], keys[2], currentValue, input, invalid))
-            .then(
-                () => testControlTextbox(
-                    controls[3], keys[3], currentValue, input, invalid));
-      };
-
       return finishSetup().then(() => {
         const controls = getControls();
         // Set a shorter delay for testing so the test doesn't take too
         // long.
         controls.forEach(c => {
-          c.getInput().setAttribute('data-timeout-delay', 10);
+          c.getInput().setAttribute('data-timeout-delay', 1);
         });
         model.set(
             'settings.margins.value',
@@ -465,6 +478,65 @@
       });
     });
 
+    // Test that setting the margin controls with their textbox inputs updates
+    // the custom margins setting, using a metric measurement system with a ','
+    // as the decimal delimiter and '.' as the thousands delimiter. Regression
+    // test for https://crbug.com/1005816.
+    test(assert(TestNames.SetControlsWithTextboxMetric), function() {
+      measurementSystem = new print_preview.MeasurementSystem(
+          '.', ',', print_preview.MeasurementSystemUnitType.METRIC);
+      return finishSetup().then(() => {
+        const controls = getControls();
+        // Set a shorter delay for testing so the test doesn't take too
+        // long.
+        controls.forEach(c => {
+          c.getInput().setAttribute('data-timeout-delay', 1);
+        });
+        model.set(
+            'settings.margins.value',
+            print_preview.ticket_items.MarginsTypeValue.CUSTOM);
+        Polymer.dom.flush();
+
+        // Verify entering a new value updates the settings.
+        // Then verify entering an invalid value invalidates the control
+        // and does not update the settings.
+        const pointsPerMM = pointsPerInch / 25.4;
+        const newMargin1 = '50,0';
+        const newMargin1Pts = Math.round(50 * pointsPerMM);
+        const newMargin2 = ',9';
+        const newMargin2Pts = Math.round(.9 * pointsPerMM);
+        const newMargin3 = '60';
+        const newMargin3Pts = Math.round(60 * pointsPerMM);
+        const maxTopMargin = container.pageSize.height - newMargin3Pts -
+            72 /* MINIMUM_DISTANCE, see margin_control.js */;
+        return testAllTextboxes(
+                   controls, defaultMarginPts, newMargin1, false, newMargin1Pts)
+            .then(
+                () => testAllTextboxes(
+                    controls, newMargin1Pts, 'abc', true, newMargin1Pts))
+            .then(
+                () => testAllTextboxes(
+                    controls, newMargin1Pts, '50,2abc', true, newMargin1Pts))
+            .then(
+                () => testAllTextboxes(
+                    controls, newMargin1Pts, '10,   2', true, newMargin1Pts))
+            .then(
+                () => testAllTextboxes(
+                    controls, newMargin1Pts, newMargin2, false, newMargin2Pts))
+            .then(
+                () => testAllTextboxes(
+                    controls, newMargin2Pts, newMargin3, false, newMargin3Pts))
+            .then(
+                () => testControlTextbox(
+                    controls[0], keys[0], newMargin3Pts, '1.000.000', false,
+                    maxTopMargin))
+            .then(
+                () => testControlTextbox(
+                    controls[0], keys[0], maxTopMargin, '1.000', false,
+                    maxTopMargin));
+      });
+    });
+
     // Test that if there is a custom margins sticky setting, it is restored
     // when margin setting changes.
     test(assert(TestNames.RestoreStickyMarginsAfterDefault), function() {
diff --git a/chrome/test/data/webui/print_preview/model_settings_availability_test.js b/chrome/test/data/webui/print_preview/model_settings_availability_test.js
index 3a935bc..985713c 100644
--- a/chrome/test/data/webui/print_preview/model_settings_availability_test.js
+++ b/chrome/test/data/webui/print_preview/model_settings_availability_test.js
@@ -322,12 +322,23 @@
 
       // PDF -> Save as PDF
       model.set('documentSettings.isModifiable', false);
+      model.set('documentSettings.isPdf', true);
       assertFalse(model.settings.scaling.available);
 
       // PDF -> printer
       model.set('destination', defaultDestination);
       assertTrue(model.settings.scaling.available);
       assertFalse(model.settings.scaling.setFromUi);
+
+      // Non-PDF Plugin -> Save as PDF
+      setSaveAsPdfDestination();
+      model.set('documentSettings.isPdf', false);
+      assertFalse(model.settings.scaling.available);
+
+      // Non-PDF Plugin -> printer
+      model.set('destination', defaultDestination);
+      assertFalse(model.settings.scaling.available);
+
     });
 
     test('fit to page', function() {
@@ -341,12 +352,22 @@
 
       // PDF -> Save as PDF
       model.set('documentSettings.isModifiable', false);
+      model.set('documentSettings.isPdf', true);
       assertFalse(model.settings.fitToPage.available);
 
       // PDF -> printer
       model.set('destination', defaultDestination);
       assertTrue(model.settings.fitToPage.available);
       assertFalse(model.settings.fitToPage.setFromUi);
+
+      // Non-PDF Plugin -> Save as PDF
+      setSaveAsPdfDestination();
+      model.set('documentSettings.isPdf', false);
+      assertFalse(model.settings.fitToPage.available);
+
+      // Non-PDF Plugin -> printer
+      model.set('destination', defaultDestination);
+      assertFalse(model.settings.fitToPage.available);
     });
 
     test('header footer', function() {
diff --git a/chrome/test/data/webui/print_preview/preview_generation_test.js b/chrome/test/data/webui/print_preview/preview_generation_test.js
index 775cc93..df9ceb1 100644
--- a/chrome/test/data/webui/print_preview/preview_generation_test.js
+++ b/chrome/test/data/webui/print_preview/preview_generation_test.js
@@ -132,6 +132,7 @@
     test(assert(TestNames.FitToPage), function() {
       // Set PDF document so setting is available.
       initialSettings.previewModifiable = false;
+      initialSettings.previewIsPdf = true;
       return testSimpleSetting(
           'fitToPage', false, true, 'fitToPageEnabled', false, true);
     });
diff --git a/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js b/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js
index e90dcf0..a17538f 100644
--- a/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js
+++ b/chrome/test/data/webui/print_preview/print_preview_ui_browsertest.js
@@ -893,6 +893,13 @@
 });
 
 TEST_F(
+    'PrintPreviewCustomMarginsTest', 'SetControlsWithTextboxMetric',
+    function() {
+      this.runMochaTest(
+          custom_margins_test.TestNames.SetControlsWithTextboxMetric);
+    });
+
+TEST_F(
     'PrintPreviewCustomMarginsTest', 'RestoreStickyMarginsAfterDefault',
     function() {
       this.runMochaTest(
diff --git a/chrome/test/data/webui/settings/controlled_button_tests.js b/chrome/test/data/webui/settings/controlled_button_tests.js
index e9030e5..5e9cfbb 100644
--- a/chrome/test/data/webui/settings/controlled_button_tests.js
+++ b/chrome/test/data/webui/settings/controlled_button_tests.js
@@ -74,8 +74,13 @@
   test('action-button', function() {
     assertNotEquals(
         'action-button', controlledButton.$$('cr-button').className);
-    controlledButton.actionButton = true;
+
+    let controlledActionButton = document.createElement('controlled-button');
+    controlledActionButton.pref = uncontrolledPref;
+    controlledActionButton.className = 'action-button';
+    document.body.appendChild(controlledActionButton);
     Polymer.dom.flush();
-    assertEquals('action-button', controlledButton.$$('cr-button').className);
+    assertEquals(
+        'action-button', controlledActionButton.$$('cr-button').className);
   });
 });
diff --git a/chromecast/media/audio/cast_audio_output_stream.cc b/chromecast/media/audio/cast_audio_output_stream.cc
index a517348c..50ec8ff 100644
--- a/chromecast/media/audio/cast_audio_output_stream.cc
+++ b/chromecast/media/audio/cast_audio_output_stream.cc
@@ -481,7 +481,8 @@
 
   if (!use_mixer_service_) {
     cma_wrapper_ = std::make_unique<CmaAudioOutputStream>(
-        audio_params_, device_id_, audio_manager_->cma_backend_factory());
+        audio_params_, audio_params_.GetBufferDuration(), device_id_,
+        audio_manager_->cma_backend_factory());
     POST_TO_CMA_WRAPPER(Initialize, application_session_id,
                         std::move(multiroom_info));
   } else {
diff --git a/chromecast/media/audio/cma_audio_output_stream.cc b/chromecast/media/audio/cma_audio_output_stream.cc
index 031b3be..d99252b 100644
--- a/chromecast/media/audio/cma_audio_output_stream.cc
+++ b/chromecast/media/audio/cma_audio_output_stream.cc
@@ -40,6 +40,7 @@
 
 CmaAudioOutputStream::CmaAudioOutputStream(
     const ::media::AudioParameters& audio_params,
+    base::TimeDelta buffer_duration,
     const std::string& device_id,
     CmaBackendFactory* cma_backend_factory)
     : is_audio_prefetch_(audio_params.effects() &
@@ -48,7 +49,7 @@
       device_id_(device_id),
       cma_backend_factory_(cma_backend_factory),
       timestamp_helper_(audio_params_.sample_rate()),
-      buffer_duration_(audio_params_.GetBufferDuration()),
+      buffer_duration_(buffer_duration),
       render_buffer_size_estimate_(kRenderBufferSize) {
   DCHECK(cma_backend_factory_);
   DETACH_FROM_THREAD(media_thread_checker_);
@@ -263,7 +264,7 @@
   }
   auto decoder_buffer =
       base::MakeRefCounted<DecoderBufferAdapter>(new ::media::DecoderBuffer(
-          audio_params_.GetBytesPerBuffer(::media::kSampleFormatS16)));
+          frame_count * audio_bus_->channels() * sizeof(int16_t)));
   audio_bus_->ToInterleaved<::media::SignedInt16SampleTypeTraits>(
       frame_count, reinterpret_cast<int16_t*>(decoder_buffer->writable_data()));
   decoder_buffer->set_timestamp(timestamp_helper_.GetTimestamp());
diff --git a/chromecast/media/audio/cma_audio_output_stream.h b/chromecast/media/audio/cma_audio_output_stream.h
index f4afe7a..87ea5797 100644
--- a/chromecast/media/audio/cma_audio_output_stream.h
+++ b/chromecast/media/audio/cma_audio_output_stream.h
@@ -41,6 +41,7 @@
 class CmaAudioOutputStream : public CmaBackend::Decoder::Delegate {
  public:
   CmaAudioOutputStream(const ::media::AudioParameters& audio_params,
+                       base::TimeDelta buffer_duration,
                        const std::string& device_id,
                        CmaBackendFactory* cma_backend_factory);
   ~CmaAudioOutputStream() override;
diff --git a/chromecast/media/cma/backend/BUILD.gn b/chromecast/media/cma/backend/BUILD.gn
index 210a41b..14d8f8b 100644
--- a/chromecast/media/cma/backend/BUILD.gn
+++ b/chromecast/media/cma/backend/BUILD.gn
@@ -24,7 +24,6 @@
     "cma_backend_factory.h",
     "cma_backend_factory_impl.cc",
     "cma_backend_factory_impl.h",
-    "extra_audio_stream.h",
     "media_pipeline_backend_manager.cc",
     "media_pipeline_backend_manager.h",
     "media_pipeline_backend_wrapper.cc",
diff --git a/chromecast/media/cma/backend/audio_decoder_wrapper.cc b/chromecast/media/cma/backend/audio_decoder_wrapper.cc
index bae2c130..16f164c 100644
--- a/chromecast/media/cma/backend/audio_decoder_wrapper.cc
+++ b/chromecast/media/cma/backend/audio_decoder_wrapper.cc
@@ -54,21 +54,15 @@
 }  // namespace
 
 ActiveAudioDecoderWrapper::ActiveAudioDecoderWrapper(
-    MediaPipelineBackendManager* backend_manager,
     MediaPipelineBackend::AudioDecoder* backend_decoder,
     AudioContentType type,
     MediaPipelineBackendManager::BufferDelegate* buffer_delegate)
-    : backend_manager_(backend_manager),
-      decoder_(backend_decoder),
+    : decoder_(backend_decoder),
       content_type_(type),
       buffer_delegate_(buffer_delegate),
       initialized_(false),
       delegate_active_(false),
-      global_volume_multiplier_(1.0f),
       stream_volume_multiplier_(1.0f) {
-  DCHECK(backend_manager_);
-
-  backend_manager_->AddAudioDecoder(this);
   if (buffer_delegate_) {
     buffer_delegate_->OnStreamStarted();
   }
@@ -78,27 +72,12 @@
   if (buffer_delegate_) {
     buffer_delegate_->OnStreamStopped();
   }
-  backend_manager_->RemoveAudioDecoder(this);
 }
 
 void ActiveAudioDecoderWrapper::OnInitialized() {
   initialized_ = true;
   if (!delegate_active_) {
-    float volume = stream_volume_multiplier_ * global_volume_multiplier_;
-    decoder_.SetVolume(volume);
-  }
-}
-
-void ActiveAudioDecoderWrapper::SetGlobalVolumeMultiplier(float multiplier) {
-  global_volume_multiplier_ = multiplier;
-  if (!delegate_active_) {
-    float volume = stream_volume_multiplier_ * global_volume_multiplier_;
-    if (initialized_) {
-      decoder_.SetVolume(volume);
-    }
-    if (buffer_delegate_) {
-      buffer_delegate_->OnSetVolume(volume);
-    }
+    decoder_.SetVolume(stream_volume_multiplier_);
   }
 }
 
@@ -119,8 +98,7 @@
     // Restore original volume.
     if (delegate_active_) {
       delegate_active_ = false;
-      if (!decoder_.SetVolume(stream_volume_multiplier_ *
-                              global_volume_multiplier_)) {
+      if (!decoder_.SetVolume(stream_volume_multiplier_)) {
         LOG(ERROR) << "SetVolume failed";
       }
     }
@@ -142,15 +120,14 @@
 
 bool ActiveAudioDecoderWrapper::SetVolume(float multiplier) {
   stream_volume_multiplier_ = std::max(0.0f, multiplier);
-  float volume = stream_volume_multiplier_ * global_volume_multiplier_;
   if (buffer_delegate_) {
-    buffer_delegate_->OnSetVolume(volume);
+    buffer_delegate_->OnSetVolume(stream_volume_multiplier_);
   }
 
   if (delegate_active_ || !initialized_) {
     return true;
   }
-  return decoder_.SetVolume(volume);
+  return decoder_.SetVolume(stream_volume_multiplier_);
 }
 
 ActiveAudioDecoderWrapper::RenderingDelay
@@ -169,13 +146,12 @@
 }
 
 AudioDecoderWrapper::AudioDecoderWrapper(
-    MediaPipelineBackendManager* backend_manager,
     MediaPipelineBackend::AudioDecoder* backend_decoder,
     AudioContentType type,
     MediaPipelineBackendManager::BufferDelegate* buffer_delegate)
     : decoder_revoked_(false) {
   audio_decoder_ = std::make_unique<ActiveAudioDecoderWrapper>(
-      backend_manager, backend_decoder, type, buffer_delegate);
+      backend_decoder, type, buffer_delegate);
 }
 
 AudioDecoderWrapper::AudioDecoderWrapper(AudioContentType type)
diff --git a/chromecast/media/cma/backend/audio_decoder_wrapper.h b/chromecast/media/cma/backend/audio_decoder_wrapper.h
index 22b0ab2..f47efda2 100644
--- a/chromecast/media/cma/backend/audio_decoder_wrapper.h
+++ b/chromecast/media/cma/backend/audio_decoder_wrapper.h
@@ -30,13 +30,11 @@
 class ActiveAudioDecoderWrapper : public DestructableAudioDecoder {
  public:
   ActiveAudioDecoderWrapper(
-      MediaPipelineBackendManager* backend_manager,
       MediaPipelineBackend::AudioDecoder* backend_decoder,
       AudioContentType type,
       MediaPipelineBackendManager::BufferDelegate* buffer_delegate);
   ~ActiveAudioDecoderWrapper() override;
 
-  void SetGlobalVolumeMultiplier(float multiplier);
   AudioContentType content_type() const { return content_type_; }
 
  private:
@@ -50,7 +48,6 @@
   void GetStatistics(Statistics* statistics) override;
   bool RequiresDecryption() override;
 
-  MediaPipelineBackendManager* const backend_manager_;
   AudioDecoderSoftwareWrapper decoder_;
   const AudioContentType content_type_;
 
@@ -58,7 +55,6 @@
   bool initialized_;
   bool delegate_active_;
 
-  float global_volume_multiplier_;
   float stream_volume_multiplier_;
 
   scoped_refptr<DecoderBufferBase> pushed_buffer_;
@@ -70,7 +66,6 @@
  public:
   // Create a functional "real" AudioDecoder.
   AudioDecoderWrapper(
-      MediaPipelineBackendManager* backend_manager,
       MediaPipelineBackend::AudioDecoder* backend_decoder,
       AudioContentType type,
       MediaPipelineBackendManager::BufferDelegate* buffer_delegate);
diff --git a/chromecast/media/cma/backend/extra_audio_stream.h b/chromecast/media/cma/backend/extra_audio_stream.h
deleted file mode 100644
index 643edea..0000000
--- a/chromecast/media/cma/backend/extra_audio_stream.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2019 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROMECAST_MEDIA_CMA_BACKEND_EXTRA_AUDIO_STREAM_H_
-#define CHROMECAST_MEDIA_CMA_BACKEND_EXTRA_AUDIO_STREAM_H_
-
-namespace chromecast {
-namespace media {
-
-class ExtraAudioStream {
- public:
-  virtual void SetGlobalVolumeMultiplier(float multiplier) = 0;
-
- protected:
-  virtual ~ExtraAudioStream() = default;
-};
-
-}  // namespace media
-}  // namespace chromecast
-
-#endif  // CHROMECAST_MEDIA_CMA_BACKEND_EXTRA_AUDIO_STREAM_H_
diff --git a/chromecast/media/cma/backend/media_pipeline_backend_manager.cc b/chromecast/media/cma/backend/media_pipeline_backend_manager.cc
index 2140cb8..2fba153 100644
--- a/chromecast/media/cma/backend/media_pipeline_backend_manager.cc
+++ b/chromecast/media/cma/backend/media_pipeline_backend_manager.cc
@@ -15,7 +15,6 @@
 #include "chromecast/chromecast_buildflags.h"
 #include "chromecast/media/cma/backend/audio_decoder_wrapper.h"
 #include "chromecast/media/cma/backend/cma_backend.h"
-#include "chromecast/media/cma/backend/extra_audio_stream.h"
 #include "chromecast/media/cma/backend/media_pipeline_backend_wrapper.h"
 #include "chromecast/public/volume_control.h"
 
@@ -55,10 +54,6 @@
            {AudioContentType::kOther, 0}}),
       allow_volume_feedback_observers_(
           new base::ObserverListThreadSafe<AllowVolumeFeedbackObserver>()),
-      global_volume_multipliers_({{AudioContentType::kMedia, 1.0f},
-                                  {AudioContentType::kAlarm, 1.0f},
-                                  {AudioContentType::kCommunication, 1.0f},
-                                  {AudioContentType::kOther, 1.0f}}),
       backend_wrapper_using_video_decoder_(nullptr),
       buffer_delegate_(nullptr),
       weak_factory_(this) {
@@ -67,8 +62,6 @@
          static_cast<unsigned long>(AudioContentType::kNumTypes));
   DCHECK(playing_noneffects_audio_streams_count_.size() ==
          static_cast<unsigned long>(AudioContentType::kNumTypes));
-  DCHECK(global_volume_multipliers_.size() ==
-         static_cast<unsigned long>(AudioContentType::kNumTypes));
   for (int i = 0; i < NUM_DECODER_TYPES; ++i) {
     decoder_count_[i] = 0;
   }
@@ -206,39 +199,16 @@
 
 void MediaPipelineBackendManager::AddExtraPlayingStream(
     bool sfx,
-    const AudioContentType type,
-    ExtraAudioStream* extra_audio_stream) {
-  MAKE_SURE_MEDIA_THREAD(AddExtraPlayingStream, sfx, type, extra_audio_stream);
+    const AudioContentType type) {
+  MAKE_SURE_MEDIA_THREAD(AddExtraPlayingStream, sfx, type);
   UpdatePlayingAudioCount(sfx, type, 1);
-  if (extra_audio_stream)
-    extra_audio_streams_[type].emplace(extra_audio_stream);
 }
 
 void MediaPipelineBackendManager::RemoveExtraPlayingStream(
     bool sfx,
-    const AudioContentType type,
-    ExtraAudioStream* extra_audio_stream) {
-  MAKE_SURE_MEDIA_THREAD(RemoveExtraPlayingStream, sfx, type,
-                         extra_audio_stream);
+    const AudioContentType type) {
+  MAKE_SURE_MEDIA_THREAD(RemoveExtraPlayingStream, sfx, type);
   UpdatePlayingAudioCount(sfx, type, -1);
-  if (extra_audio_stream)
-    extra_audio_streams_[type].erase(extra_audio_stream);
-}
-
-void MediaPipelineBackendManager::SetGlobalVolumeMultiplier(
-    AudioContentType type,
-    float multiplier) {
-  MAKE_SURE_MEDIA_THREAD(SetGlobalVolumeMultiplier, type, multiplier);
-  DCHECK_GE(multiplier, 0.0f);
-  global_volume_multipliers_[type] = multiplier;
-  for (auto* a : audio_decoders_) {
-    if (a->content_type() == type) {
-      a->SetGlobalVolumeMultiplier(multiplier);
-    }
-  }
-  for (auto* extra_audio_stream : extra_audio_streams_[type]) {
-    extra_audio_stream->SetGlobalVolumeMultiplier(multiplier);
-  }
 }
 
 void MediaPipelineBackendManager::SetBufferDelegate(
@@ -258,19 +228,6 @@
   }
 }
 
-void MediaPipelineBackendManager::AddAudioDecoder(
-    ActiveAudioDecoderWrapper* decoder) {
-  DCHECK(decoder);
-  audio_decoders_.insert(decoder);
-  decoder->SetGlobalVolumeMultiplier(
-      global_volume_multipliers_[decoder->content_type()]);
-}
-
-void MediaPipelineBackendManager::RemoveAudioDecoder(
-    ActiveAudioDecoderWrapper* decoder) {
-  audio_decoders_.erase(decoder);
-}
-
 void MediaPipelineBackendManager::SetPowerSaveEnabled(bool power_save_enabled) {
   MAKE_SURE_MEDIA_THREAD(SetPowerSaveEnabled, power_save_enabled);
   power_save_enabled_ = power_save_enabled;
diff --git a/chromecast/media/cma/backend/media_pipeline_backend_manager.h b/chromecast/media/cma/backend/media_pipeline_backend_manager.h
index bed7dbd..3f3c9ec 100644
--- a/chromecast/media/cma/backend/media_pipeline_backend_manager.h
+++ b/chromecast/media/cma/backend/media_pipeline_backend_manager.h
@@ -26,9 +26,7 @@
 enum class AudioContentType;
 class CastDecoderBuffer;
 class CmaBackend;
-class ExtraAudioStream;
 class MediaPipelineBackendWrapper;
-class ActiveAudioDecoderWrapper;
 class ActiveMediaPipelineBackendWrapper;
 
 // This class tracks all created media backends, tracking whether or not volume
@@ -116,18 +114,8 @@
   // CmaBackend instance (for example, direct audio output using
   // CastMediaShlib::AddDirectAudioSource()). |sfx| indicates whether or not
   // the stream is a sound effects stream (has no effect on volume feedback).
-  void AddExtraPlayingStream(bool sfx,
-                             const AudioContentType type,
-                             ExtraAudioStream* extra_audio_stream = nullptr);
-  void RemoveExtraPlayingStream(bool sfx,
-                                const AudioContentType type,
-                                ExtraAudioStream* extra_audio_stream = nullptr);
-
-  // Sets a global multiplier for output volume for streams of the given |type|.
-  // The multiplier may be any value >= 0; if the resulting volume for an
-  // individual stream would be > 1.0, that stream's volume is clamped to 1.0.
-  // The default multiplier is 1.0. May be called on any thread.
-  void SetGlobalVolumeMultiplier(AudioContentType type, float multiplier);
+  void AddExtraPlayingStream(bool sfx, const AudioContentType type);
+  void RemoveExtraPlayingStream(bool sfx, const AudioContentType type);
 
   // |buffer_delegate| will get notified for all buffers on the media stream.
   // |buffer_delegate| must outlive |this|.
@@ -144,10 +132,6 @@
 
  private:
   friend class ActiveMediaPipelineBackendWrapper;
-  friend class ActiveAudioDecoderWrapper;
-
-  void AddAudioDecoder(ActiveAudioDecoderWrapper* decoder);
-  void RemoveAudioDecoder(ActiveAudioDecoderWrapper* decoder);
 
   // Backend wrapper instances must use these APIs when allocating and releasing
   // decoder objects, so we can enforce global limit on #concurrent decoders.
@@ -177,11 +161,6 @@
   scoped_refptr<base::ObserverListThreadSafe<AllowVolumeFeedbackObserver>>
       allow_volume_feedback_observers_;
 
-  base::flat_set<ActiveAudioDecoderWrapper*> audio_decoders_;
-  base::flat_map<AudioContentType, base::flat_set<ExtraAudioStream*>>
-      extra_audio_streams_;
-  base::flat_map<AudioContentType, float> global_volume_multipliers_;
-
   // Previously issued MediaPipelineBackendWrapper that uses a video decoder.
   MediaPipelineBackendWrapper* backend_wrapper_using_video_decoder_;
 
diff --git a/chromecast/media/cma/backend/media_pipeline_backend_wrapper.cc b/chromecast/media/cma/backend/media_pipeline_backend_wrapper.cc
index 5907af6..aa86ec51 100644
--- a/chromecast/media/cma/backend/media_pipeline_backend_wrapper.cc
+++ b/chromecast/media/cma/backend/media_pipeline_backend_wrapper.cc
@@ -195,7 +195,7 @@
   }
 
   auto audio_decoder = std::make_unique<AudioDecoderWrapper>(
-      backend_manager_, real_decoder, content_type_, delegate);
+      real_decoder, content_type_, delegate);
   audio_decoder_ptr_ = audio_decoder.get();
   return audio_decoder;
 }
diff --git a/chromecast/media/cma/backend/volume_control.cc b/chromecast/media/cma/backend/volume_control.cc
index 7bf8416..744365a 100644
--- a/chromecast/media/cma/backend/volume_control.cc
+++ b/chromecast/media/cma/backend/volume_control.cc
@@ -6,7 +6,6 @@
 
 #include <algorithm>
 #include <cmath>
-#include <map>
 #include <memory>
 #include <string>
 #include <utility>
@@ -14,6 +13,7 @@
 
 #include "base/bind.h"
 #include "base/bind_helpers.h"
+#include "base/containers/flat_map.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/location.h"
@@ -168,6 +168,24 @@
                                   false /* from_system */));
   }
 
+  void SetVolumeMultiplier(AudioContentType type, float multiplier) {
+    if (type == AudioContentType::kOther) {
+      NOTREACHED() << "Can't set volume multiplier for content type kOther";
+      return;
+    }
+
+    if (BUILDFLAG(SYSTEM_OWNS_VOLUME)) {
+      LOG(INFO) << "Ignore global volume multiplier since volume is externally "
+                << "controlled";
+      return;
+    }
+
+    thread_.task_runner()->PostTask(
+        FROM_HERE,
+        base::BindOnce(&VolumeControlInternal::SetVolumeMultiplierOnThread,
+                       base::Unretained(this), type, multiplier));
+  }
+
   bool IsMuted(AudioContentType type) {
     base::AutoLock lock(volume_lock_);
     return muted_[type];
@@ -214,6 +232,7 @@
                       AudioContentType::kCommunication}) {
       CHECK(stored_values_.GetDouble(ContentTypeToDbFSKey(type), &dbfs));
       volumes_[type] = VolumeControl::DbFSToVolume(dbfs);
+      volume_multipliers_[type] = 1.0f;
       if (BUILDFLAG(SYSTEM_OWNS_VOLUME)) {
         // If ALSA owns volume, our internal mixer should not apply any scaling
         // multiplier.
@@ -251,6 +270,7 @@
     DCHECK(thread_.task_runner()->BelongsToCurrentThread());
     DCHECK(type != AudioContentType::kOther);
     DCHECK(!from_system || type == AudioContentType::kMedia);
+    DCHECK(volume_multipliers_.find(type) != volume_multipliers_.end());
 
     {
       base::AutoLock lock(volume_lock_);
@@ -266,7 +286,8 @@
 
     float dbfs = VolumeControl::VolumeToDbFS(level);
     if (!BUILDFLAG(SYSTEM_OWNS_VOLUME)) {
-      StreamMixer::Get()->SetVolume(type, DbFsToScale(dbfs));
+      StreamMixer::Get()->SetVolume(
+          type, DbFsToScale(dbfs) * volume_multipliers_[type]);
     }
 
     if (!from_system && type == AudioContentType::kMedia) {
@@ -284,6 +305,17 @@
     SerializeJsonToFile(storage_path_, stored_values_);
   }
 
+  void SetVolumeMultiplierOnThread(AudioContentType type, float multiplier) {
+    DCHECK(thread_.task_runner()->BelongsToCurrentThread());
+    DCHECK(type != AudioContentType::kOther);
+    DCHECK(!BUILDFLAG(SYSTEM_OWNS_VOLUME));
+
+    volume_multipliers_[type] = multiplier;
+    float scale =
+        DbFsToScale(VolumeControl::VolumeToDbFS(volumes_[type])) * multiplier;
+    StreamMixer::Get()->SetVolume(type, scale);
+  }
+
   void SetMutedOnThread(VolumeChangeSource source,
                         AudioContentType type,
                         bool muted,
@@ -353,8 +385,9 @@
   base::DictionaryValue stored_values_;
 
   base::Lock volume_lock_;
-  std::map<AudioContentType, float> volumes_;
-  std::map<AudioContentType, bool> muted_;
+  base::flat_map<AudioContentType, float> volumes_;
+  base::flat_map<AudioContentType, float> volume_multipliers_;
+  base::flat_map<AudioContentType, bool> muted_;
 
   base::Lock observer_lock_;
   std::vector<VolumeObserver*> volume_observers_;
@@ -408,6 +441,12 @@
 }
 
 // static
+void VolumeControl::SetVolumeMultiplier(AudioContentType type,
+                                        float multiplier) {
+  GetVolumeControl().SetVolumeMultiplier(type, multiplier);
+}
+
+// static
 bool VolumeControl::IsMuted(AudioContentType type) {
   return GetVolumeControl().IsMuted(type);
 }
diff --git a/chromecast/public/volume_control.h b/chromecast/public/volume_control.h
index 042a0b69..ae07974 100644
--- a/chromecast/public/volume_control.h
+++ b/chromecast/public/volume_control.h
@@ -85,6 +85,11 @@
                         AudioContentType type,
                         float level);
 
+  // Sets a multiplier on the attenuation level for a given audio stream type.
+  // Used for stereo pair balance.
+  static void SetVolumeMultiplier(AudioContentType type, float multiplier)
+      __attribute__((weak));
+
   // Gets/sets the mute state for a given audio stream |type|.
   // AudioContentType::kOther is not a valid |type| for these methods.
   static bool IsMuted(AudioContentType type);
diff --git a/chromeos/geolocation/simple_geolocation_unittest.cc b/chromeos/geolocation/simple_geolocation_unittest.cc
index 6beea37..abba003 100644
--- a/chromeos/geolocation/simple_geolocation_unittest.cc
+++ b/chromeos/geolocation/simple_geolocation_unittest.cc
@@ -115,12 +115,12 @@
 
  private:
   void AddResponseWithCode(int error_code) {
-    network::ResourceResponseHead response_head;
-    response_head.headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
-    response_head.headers->AddHeader("Content-Type: application/json");
+    auto response_head = network::mojom::URLResponseHead::New();
+    response_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+    response_head->headers->AddHeader("Content-Type: application/json");
     // If AddResponse() is called multiple times for the same URL, the last
     // one is the one used so there is no need for ClearResponses().
-    AddResponse(url_, response_head, response_,
+    AddResponse(url_, std::move(response_head), response_,
                 network::URLLoaderCompletionStatus(error_code));
   }
 
diff --git a/chromeos/printing/ppd_provider_unittest.cc b/chromeos/printing/ppd_provider_unittest.cc
index 274eaa7..3b40b57 100644
--- a/chromeos/printing/ppd_provider_unittest.cc
+++ b/chromeos/printing/ppd_provider_unittest.cc
@@ -112,8 +112,8 @@
       }
 
       loader_factory_.AddResponse(FileToURL(entry.first),
-                                  network::ResourceResponseHead(), entry.second,
-                                  status);
+                                  network::mojom::URLResponseHead::New(),
+                                  entry.second, status);
     }
   }
 
@@ -197,7 +197,8 @@
     network::URLLoaderCompletionStatus status(net::ERR_ADDRESS_UNREACHABLE);
     for (const auto& entry : server_contents()) {
       loader_factory_.AddResponse(FileToURL(entry.first),
-                                  network::ResourceResponseHead(), "", status);
+                                  network::mojom::URLResponseHead::New(), "",
+                                  status);
     }
   }
 
diff --git a/chromeos/services/device_sync/cryptauth_api_call_flow_unittest.cc b/chromeos/services/device_sync/cryptauth_api_call_flow_unittest.cc
index b99511e..57480bd 100644
--- a/chromeos/services/device_sync/cryptauth_api_call_flow_unittest.cc
+++ b/chromeos/services/device_sync/cryptauth_api_call_flow_unittest.cc
@@ -172,17 +172,17 @@
       base::Optional<int> response_code = base::nullopt,
       const base::Optional<std::string>& response_string = base::nullopt) {
     network::URLLoaderCompletionStatus completion_status(error);
-    network::ResourceResponseHead response_head;
+    auto response_head = network::mojom::URLResponseHead::New();
     std::string content;
     if (error == net::OK) {
-      response_head = network::CreateResourceResponseHead(
+      response_head = network::CreateURLResponseHead(
           static_cast<net::HttpStatusCode>(*response_code));
       content = *response_string;
     }
 
     // Use kUrlMatchPrefix flag to match URL without query parameters.
     EXPECT_TRUE(test_url_loader_factory_.SimulateResponseForPendingRequest(
-        GURL(kRequestUrl), completion_status, response_head, content,
+        GURL(kRequestUrl), completion_status, std::move(response_head), content,
         network::TestURLLoaderFactory::ResponseMatchFlags::kUrlMatchPrefix));
 
     task_environment_.RunUntilIdle();
@@ -196,17 +196,17 @@
       base::Optional<int> response_code = base::nullopt,
       const base::Optional<std::string>& response_string = base::nullopt) {
     network::URLLoaderCompletionStatus completion_status(error);
-    network::ResourceResponseHead response_head;
+    auto response_head = network::mojom::URLResponseHead::New();
     std::string content;
     if (error == net::OK) {
-      response_head = network::CreateResourceResponseHead(
+      response_head = network::CreateURLResponseHead(
           static_cast<net::HttpStatusCode>(*response_code));
       content = *response_string;
     }
 
     // Use kUrlMatchPrefix flag to match URL without query parameters.
     EXPECT_TRUE(test_url_loader_factory_.SimulateResponseForPendingRequest(
-        GURL(kRequestUrl), completion_status, response_head, content,
+        GURL(kRequestUrl), completion_status, std::move(response_head), content,
         network::TestURLLoaderFactory::ResponseMatchFlags::kUrlMatchPrefix));
 
     task_environment_.RunUntilIdle();
diff --git a/chromeos/timezone/timezone_unittest.cc b/chromeos/timezone/timezone_unittest.cc
index 8eb98f53..e207a61 100644
--- a/chromeos/timezone/timezone_unittest.cc
+++ b/chromeos/timezone/timezone_unittest.cc
@@ -113,12 +113,12 @@
 
  private:
   void AddResponseWithCode(int error_code) {
-    network::ResourceResponseHead response_head;
-    response_head.headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
-    response_head.headers->AddHeader("Content-Type: application/json");
+    auto response_head = network::mojom::URLResponseHead::New();
+    response_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+    response_head->headers->AddHeader("Content-Type: application/json");
     // If AddResponse() is called multiple times for the same URL, the last
     // one is the one used so there is no need for ClearResponses().
-    AddResponse(url_, response_head, response_,
+    AddResponse(url_, std::move(response_head), response_,
                 network::URLLoaderCompletionStatus(error_code));
   }
 
diff --git a/components/assist_ranker/ranker_model_loader_impl_unittest.cc b/components/assist_ranker/ranker_model_loader_impl_unittest.cc
index c472664..770277a 100644
--- a/components/assist_ranker/ranker_model_loader_impl_unittest.cc
+++ b/components/assist_ranker/ranker_model_loader_impl_unittest.cc
@@ -187,7 +187,7 @@
   test_loader_factory_.AddResponse(invalid_model_url_.spec(),
                                    kInvalidModelData);
   test_loader_factory_.AddResponse(
-      failed_model_url_, network::ResourceResponseHead(), "",
+      failed_model_url_, network::mojom::URLResponseHead::New(), "",
       network::URLLoaderCompletionStatus(net::HTTP_INTERNAL_SERVER_ERROR));
 }
 
diff --git a/components/autofill/core/browser/BUILD.gn b/components/autofill/core/browser/BUILD.gn
index e2887ae..def7735 100644
--- a/components/autofill/core/browser/BUILD.gn
+++ b/components/autofill/core/browser/BUILD.gn
@@ -295,8 +295,10 @@
       "ui/mobile_label_formatter.h",
       "ui/payments/card_expiration_date_fix_flow_view_delegate_mobile.cc",
       "ui/payments/card_expiration_date_fix_flow_view_delegate_mobile.h",
-      "ui/payments/card_name_fix_flow_view_delegate_mobile.cc",
-      "ui/payments/card_name_fix_flow_view_delegate_mobile.h",
+      "ui/payments/card_name_fix_flow_controller.h",
+      "ui/payments/card_name_fix_flow_controller_impl.cc",
+      "ui/payments/card_name_fix_flow_controller_impl.h",
+      "ui/payments/card_name_fix_flow_view.h",
     ]
   }
 
@@ -601,6 +603,7 @@
     sources += [
       "autofill_assistant_unittest.cc",
       "ui/mobile_label_formatter_unittest.cc",
+      "ui/payments/card_name_fix_flow_controller_impl_unittest.cc",
     ]
   }
 
diff --git a/components/autofill/core/browser/autofill_download_manager_unittest.cc b/components/autofill/core/browser/autofill_download_manager_unittest.cc
index d3fbc34..2a710a9 100644
--- a/components/autofill/core/browser/autofill_download_manager_unittest.cc
+++ b/components/autofill/core/browser/autofill_download_manager_unittest.cc
@@ -408,7 +408,7 @@
   // Request 2: Unsuccessful upload.
   request = test_url_loader_factory_.GetPendingRequest(2);
   test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList(
-      request, network::CreateResourceResponseHead(net::HTTP_NOT_FOUND),
+      request, network::CreateURLResponseHead(net::HTTP_NOT_FOUND),
       responses[2], network::URLLoaderCompletionStatus(net::OK));
   histogram.ExpectBucketCount("Autofill.Upload.HttpResponseOrErrorCode",
                               net::HTTP_NOT_FOUND, 1);
@@ -464,8 +464,7 @@
                                AutofillMetrics::QUERY_SENT, 2);
   histogram.ExpectUniqueSample("Autofill.Query.Method", METHOD_GET, 2);
   test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList(
-      request,
-      network::CreateResourceResponseHead(net::HTTP_INTERNAL_SERVER_ERROR),
+      request, network::CreateURLResponseHead(net::HTTP_INTERNAL_SERVER_ERROR),
       responses[0], network::URLLoaderCompletionStatus(net::OK));
   histogram.ExpectBucketCount("Autofill.Query.HttpResponseOrErrorCode",
                               net::HTTP_INTERNAL_SERVER_ERROR, 1);
@@ -489,7 +488,7 @@
   network::URLLoaderCompletionStatus status(net::OK);
   status.exists_in_cache = true;
   test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList(
-      request, network::CreateResourceResponseHead(net::HTTP_OK), responses[0],
+      request, network::CreateURLResponseHead(net::HTTP_OK), responses[0],
       status);
 
   // Check Request 5.
@@ -845,9 +844,8 @@
 
   // Request error incurs a retry after 1 second.
   test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList(
-      request,
-      network::CreateResourceResponseHead(net::HTTP_INTERNAL_SERVER_ERROR), "",
-      network::URLLoaderCompletionStatus(net::OK));
+      request, network::CreateURLResponseHead(net::HTTP_INTERNAL_SERVER_ERROR),
+      "", network::URLLoaderCompletionStatus(net::OK));
 
   EXPECT_EQ(1U, responses_.size());
   EXPECT_LT(download_manager_.loader_backoff_.GetTimeUntilRelease(),
@@ -864,7 +862,7 @@
   // Next error incurs a retry after 2 seconds.
   test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList(
       request,
-      network::CreateResourceResponseHead(net::HTTP_REQUEST_ENTITY_TOO_LARGE),
+      network::CreateURLResponseHead(net::HTTP_REQUEST_ENTITY_TOO_LARGE),
       "<html></html>", network::URLLoaderCompletionStatus(net::OK));
 
   EXPECT_EQ(2U, responses_.size());
@@ -915,9 +913,8 @@
 
   // Error incurs a retry after 1 second.
   test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList(
-      request,
-      network::CreateResourceResponseHead(net::HTTP_INTERNAL_SERVER_ERROR), "",
-      network::URLLoaderCompletionStatus(net::OK));
+      request, network::CreateURLResponseHead(net::HTTP_INTERNAL_SERVER_ERROR),
+      "", network::URLLoaderCompletionStatus(net::OK));
   EXPECT_EQ(1U, responses_.size());
   EXPECT_LT(download_manager_.loader_backoff_.GetTimeUntilRelease(),
             base::TimeDelta::FromMilliseconds(1100));
@@ -959,8 +956,8 @@
   request = test_url_loader_factory_.GetPendingRequest(2);
   test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList(
       request,
-      network::CreateResourceResponseHead(net::HTTP_REQUEST_ENTITY_TOO_LARGE),
-      "", network::URLLoaderCompletionStatus(net::OK));
+      network::CreateURLResponseHead(net::HTTP_REQUEST_ENTITY_TOO_LARGE), "",
+      network::URLLoaderCompletionStatus(net::OK));
   ASSERT_EQ(test_url_loader_factory_.NumPending(), 0);
   histogram.ExpectBucketCount("Autofill.Upload.HttpResponseOrErrorCode",
                               net::HTTP_REQUEST_ENTITY_TOO_LARGE, 1);
@@ -1012,7 +1009,7 @@
     // Request error incurs a retry after 1 second.
     test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList(
         request,
-        network::CreateResourceResponseHead(net::HTTP_INTERNAL_SERVER_ERROR),
+        network::CreateURLResponseHead(net::HTTP_INTERNAL_SERVER_ERROR),
         "<html></html>", network::URLLoaderCompletionStatus(net::OK));
 
     EXPECT_EQ(1U, responses_.size());
@@ -1089,8 +1086,8 @@
     // Simulate a server failure.
     test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList(
         request,
-        network::CreateResourceResponseHead(net::HTTP_INTERNAL_SERVER_ERROR),
-        "", network::URLLoaderCompletionStatus(net::OK));
+        network::CreateURLResponseHead(net::HTTP_INTERNAL_SERVER_ERROR), "",
+        network::URLLoaderCompletionStatus(net::OK));
 
     // Check that it was a failure.
     ASSERT_EQ(1U, responses_.size());
diff --git a/components/autofill/core/browser/autofill_metrics_unittest.cc b/components/autofill/core/browser/autofill_metrics_unittest.cc
index 33cc102..e72ad9ed 100644
--- a/components/autofill/core/browser/autofill_metrics_unittest.cc
+++ b/components/autofill/core/browser/autofill_metrics_unittest.cc
@@ -8434,9 +8434,9 @@
     base::HistogramTester histogram_tester;
     AutofillMetrics::LogUserHappinessBySecurityLevel(
         AutofillMetrics::FIELD_WAS_AUTOFILLED, PASSWORD_FORM,
-        security_state::SecurityLevel::HTTP_SHOW_WARNING);
+        security_state::SecurityLevel::WARNING);
     histogram_tester.ExpectBucketCount(
-        "Autofill.UserHappiness.Password.HTTP_SHOW_WARNING",
+        "Autofill.UserHappiness.Password.WARNING",
         AutofillMetrics::FIELD_WAS_AUTOFILLED, 1);
   }
 
@@ -8496,16 +8496,14 @@
   // Simulate suggestions shown twice with separate popups.
   {
     base::HistogramTester histogram_tester;
-    autofill_client_.set_security_level(
-        security_state::SecurityLevel::HTTP_SHOW_WARNING);
+    autofill_client_.set_security_level(security_state::SecurityLevel::WARNING);
     autofill_manager_->DidShowSuggestions(true, form, field);
     autofill_manager_->DidShowSuggestions(true, form, field);
-    histogram_tester.ExpectBucketCount(
-        "Autofill.UserHappiness.Address.HTTP_SHOW_WARNING",
-        AutofillMetrics::SUGGESTIONS_SHOWN, 2);
-    histogram_tester.ExpectBucketCount(
-        "Autofill.UserHappiness.Address.HTTP_SHOW_WARNING",
-        AutofillMetrics::SUGGESTIONS_SHOWN_ONCE, 1);
+    histogram_tester.ExpectBucketCount("Autofill.UserHappiness.Address.WARNING",
+                                       AutofillMetrics::SUGGESTIONS_SHOWN, 2);
+    histogram_tester.ExpectBucketCount("Autofill.UserHappiness.Address.WARNING",
+                                       AutofillMetrics::SUGGESTIONS_SHOWN_ONCE,
+                                       1);
   }
 }
 
@@ -8751,9 +8749,9 @@
     base::HistogramTester histogram_tester;
     AutofillMetrics::LogSaveCardPromptMetricBySecurityLevel(
         AutofillMetrics::SAVE_CARD_PROMPT_END_ACCEPTED, /*is_uploading=*/true,
-        security_state::SecurityLevel::HTTP_SHOW_WARNING);
+        security_state::SecurityLevel::WARNING);
     histogram_tester.ExpectBucketCount(
-        "Autofill.SaveCreditCardPrompt.Upload.HTTP_SHOW_WARNING",
+        "Autofill.SaveCreditCardPrompt.Upload.WARNING",
         AutofillMetrics::SAVE_CARD_PROMPT_END_ACCEPTED, 1);
   }
 
diff --git a/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller.h b/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller.h
new file mode 100644
index 0000000..dfbc2d3
--- /dev/null
+++ b/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller.h
@@ -0,0 +1,32 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_CONTROLLER_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_CONTROLLER_H_
+
+#include "base/strings/string16.h"
+
+namespace autofill {
+
+// Enables the user to accept or deny cardholder name fix flow prompt.
+// Only used on mobile.
+class CardNameFixFlowController {
+ public:
+  virtual ~CardNameFixFlowController() {}
+
+  // Interaction.
+  virtual void OnConfirmNameDialogClosed() = 0;
+  virtual void OnNameAccepted(const base::string16& name) = 0;
+  virtual void OnDismissed() = 0;
+
+  // State.
+  virtual int GetIconId() const = 0;
+  virtual base::string16 GetInferredCardholderName() const = 0;
+  virtual base::string16 GetSaveButtonLabel() const = 0;
+  virtual base::string16 GetTitleText() const = 0;
+};
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_CONTROLLER_H_
diff --git a/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.cc b/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.cc
new file mode 100644
index 0000000..dc05548f
--- /dev/null
+++ b/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.cc
@@ -0,0 +1,102 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.h"
+
+#include <utility>
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/values.h"
+#include "build/branding_buildflags.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/ui/payments/card_name_fix_flow_view.h"
+#include "components/grit/components_scaled_resources.h"
+#include "components/strings/grit/components_strings.h"
+#include "ui/base/l10n/l10n_util.h"
+
+namespace autofill {
+
+CardNameFixFlowControllerImpl::CardNameFixFlowControllerImpl() {}
+
+CardNameFixFlowControllerImpl::~CardNameFixFlowControllerImpl() {
+  if (card_name_fix_flow_view_)
+    card_name_fix_flow_view_->ControllerGone();
+
+  if (shown_ && !had_user_interaction_) {
+    AutofillMetrics::LogCardholderNameFixFlowPromptEvent(
+        AutofillMetrics::
+            CARDHOLDER_NAME_FIX_FLOW_PROMPT_CLOSED_WITHOUT_INTERACTION);
+  }
+}
+
+void CardNameFixFlowControllerImpl::Show(
+    CardNameFixFlowView* card_name_fix_flow_view,
+    const base::string16& inferred_cardholder_name,
+    base::OnceCallback<void(const base::string16&)> name_accepted_callback) {
+  DCHECK(!name_accepted_callback.is_null());
+  DCHECK(card_name_fix_flow_view);
+
+  if (card_name_fix_flow_view_)
+    card_name_fix_flow_view_->ControllerGone();
+  card_name_fix_flow_view_ = card_name_fix_flow_view;
+
+  name_accepted_callback_ = std::move(name_accepted_callback);
+
+  inferred_cardholder_name_ = inferred_cardholder_name;
+  AutofillMetrics::LogSaveCardCardholderNamePrefilled(
+      !inferred_cardholder_name_.empty());
+
+  card_name_fix_flow_view_->Show();
+  AutofillMetrics::LogCardholderNameFixFlowPromptEvent(
+      AutofillMetrics::CARDHOLDER_NAME_FIX_FLOW_PROMPT_SHOWN);
+  shown_ = true;
+}
+
+void CardNameFixFlowControllerImpl::OnConfirmNameDialogClosed() {
+  card_name_fix_flow_view_ = nullptr;
+}
+
+void CardNameFixFlowControllerImpl::OnNameAccepted(const base::string16& name) {
+  AutofillMetrics::LogCardholderNameFixFlowPromptEvent(
+      AutofillMetrics::CARDHOLDER_NAME_FIX_FLOW_PROMPT_ACCEPTED);
+  had_user_interaction_ = true;
+  AutofillMetrics::LogSaveCardCardholderNameWasEdited(
+      inferred_cardholder_name_ != name);
+  base::string16 trimmed_name;
+  base::TrimWhitespace(name, base::TRIM_ALL, &trimmed_name);
+  std::move(name_accepted_callback_).Run(trimmed_name);
+}
+
+void CardNameFixFlowControllerImpl::OnDismissed() {
+  AutofillMetrics::LogCardholderNameFixFlowPromptEvent(
+      AutofillMetrics::CARDHOLDER_NAME_FIX_FLOW_PROMPT_DISMISSED);
+  had_user_interaction_ = true;
+}
+
+int CardNameFixFlowControllerImpl::GetIconId() const {
+#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
+  return IDR_AUTOFILL_GOOGLE_PAY_WITH_DIVIDER;
+#else
+  return 0;
+#endif
+}
+
+base::string16 CardNameFixFlowControllerImpl::GetInferredCardholderName()
+    const {
+  return inferred_cardholder_name_;
+}
+
+base::string16 CardNameFixFlowControllerImpl::GetSaveButtonLabel() const {
+  return l10n_util::GetStringUTF16(
+      IDS_AUTOFILL_FIX_FLOW_PROMPT_SAVE_CARD_LABEL);
+}
+
+base::string16 CardNameFixFlowControllerImpl::GetTitleText() const {
+  return l10n_util::GetStringUTF16(
+      IDS_AUTOFILL_SAVE_CARD_CARDHOLDER_NAME_FIX_FLOW_HEADER);
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.h b/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.h
new file mode 100644
index 0000000..6acee1d
--- /dev/null
+++ b/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.h
@@ -0,0 +1,58 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_CONTROLLER_IMPL_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_CONTROLLER_IMPL_H_
+
+#include <string>
+
+#include "base/callback.h"
+#include "base/macros.h"
+#include "base/strings/string16.h"
+#include "components/autofill/core/browser/ui/payments/card_name_fix_flow_controller.h"
+
+namespace autofill {
+
+class CardNameFixFlowView;
+
+class CardNameFixFlowControllerImpl : public CardNameFixFlowController {
+ public:
+  CardNameFixFlowControllerImpl();
+  ~CardNameFixFlowControllerImpl() override;
+
+  void Show(CardNameFixFlowView* card_name_fix_flow_view,
+            const base::string16& inferred_cardholder_name,
+            base::OnceCallback<void(const base::string16&)> name_callback);
+
+  // CardNameFixFlowController implementation.
+  void OnConfirmNameDialogClosed() override;
+  void OnNameAccepted(const base::string16& name) override;
+  void OnDismissed() override;
+  int GetIconId() const override;
+  base::string16 GetInferredCardholderName() const override;
+  base::string16 GetSaveButtonLabel() const override;
+  base::string16 GetTitleText() const override;
+
+ private:
+  // Inferred cardholder name from Gaia account.
+  base::string16 inferred_cardholder_name_;
+
+  // View that displays the fix flow prompt.
+  CardNameFixFlowView* card_name_fix_flow_view_ = nullptr;
+
+  // The callback to call once user confirms their name through the fix flow.
+  base::OnceCallback<void(const base::string16&)> name_accepted_callback_;
+
+  // Whether the prompt was shown to the user.
+  bool shown_ = false;
+
+  // Whether the user explicitly accepted or dismissed this prompt.
+  bool had_user_interaction_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(CardNameFixFlowControllerImpl);
+};
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_CONTROLLER_IMPL_H_
diff --git a/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl_unittest.cc b/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl_unittest.cc
new file mode 100644
index 0000000..c6dc583e
--- /dev/null
+++ b/components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl_unittest.cc
@@ -0,0 +1,147 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "components/autofill/core/browser/ui/payments/card_name_fix_flow_controller_impl.h"
+
+#include <stddef.h>
+#include <memory>
+
+#include "base/bind.h"
+#include "base/macros.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/test/metrics/histogram_tester.h"
+#include "components/autofill/core/browser/autofill_metrics.h"
+#include "components/autofill/core/browser/autofill_test_utils.h"
+#include "components/autofill/core/browser/ui/payments/card_name_fix_flow_view.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace autofill {
+
+class TestCardNameFixFlowView : public CardNameFixFlowView {
+ public:
+  void Show() override {}
+  void ControllerGone() override {}
+};
+
+class CardNameFixFlowControllerImplGenericTest {
+ public:
+  CardNameFixFlowControllerImplGenericTest() {}
+
+  void ShowPromptWithInferredName() {
+    inferred_name_ = base::ASCIIToUTF16("John Doe");
+    ShowPrompt();
+  }
+
+  void ShowPromptWithoutInferredName() {
+    inferred_name_ = base::ASCIIToUTF16("");
+    ShowPrompt();
+  }
+
+  void AcceptWithInferredName() { controller_->OnNameAccepted(inferred_name_); }
+
+  void AcceptWithEditedName() {
+    controller_->OnNameAccepted(base::ASCIIToUTF16("Edited Name"));
+  }
+
+ protected:
+  std::unique_ptr<TestCardNameFixFlowView> test_card_name_fix_flow_view_;
+  std::unique_ptr<CardNameFixFlowControllerImpl> controller_;
+  base::string16 inferred_name_;
+  base::string16 accepted_name_;
+  base::WeakPtrFactory<CardNameFixFlowControllerImplGenericTest>
+      weak_ptr_factory_{this};
+
+ private:
+  void OnNameAccepted(const base::string16& name) { accepted_name_ = name; }
+
+  void ShowPrompt() {
+    controller_->Show(
+        test_card_name_fix_flow_view_.get(), inferred_name_,
+        base::BindOnce(
+            &CardNameFixFlowControllerImplGenericTest::OnNameAccepted,
+            weak_ptr_factory_.GetWeakPtr()));
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(CardNameFixFlowControllerImplGenericTest);
+};
+
+class CardNameFixFlowControllerImplTest
+    : public CardNameFixFlowControllerImplGenericTest,
+      public testing::Test {
+ public:
+  CardNameFixFlowControllerImplTest() {}
+  ~CardNameFixFlowControllerImplTest() override {}
+
+  void SetUp() override {
+    test_card_name_fix_flow_view_.reset(new TestCardNameFixFlowView());
+    controller_.reset(new CardNameFixFlowControllerImpl());
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(CardNameFixFlowControllerImplTest);
+};
+
+TEST_F(CardNameFixFlowControllerImplTest, LogShown) {
+  base::HistogramTester histogram_tester;
+  ShowPromptWithInferredName();
+
+  histogram_tester.ExpectUniqueSample(
+      "Autofill.CardholderNameFixFlowPrompt.Events",
+      AutofillMetrics::CARDHOLDER_NAME_FIX_FLOW_PROMPT_SHOWN, 1);
+}
+
+TEST_F(CardNameFixFlowControllerImplTest, LogPrefilled) {
+  base::HistogramTester histogram_tester;
+  ShowPromptWithInferredName();
+
+  histogram_tester.ExpectBucketCount("Autofill.SaveCardCardholderNamePrefilled",
+                                     true, 1);
+}
+
+TEST_F(CardNameFixFlowControllerImplTest, LogNotPrefilled) {
+  base::HistogramTester histogram_tester;
+  ShowPromptWithoutInferredName();
+
+  histogram_tester.ExpectBucketCount("Autofill.SaveCardCardholderNamePrefilled",
+                                     false, 1);
+}
+
+TEST_F(CardNameFixFlowControllerImplTest, LogAccepted) {
+  base::HistogramTester histogram_tester;
+  ShowPromptWithInferredName();
+  AcceptWithInferredName();
+
+  histogram_tester.ExpectBucketCount(
+      "Autofill.CardholderNameFixFlowPrompt.Events",
+      AutofillMetrics::CARDHOLDER_NAME_FIX_FLOW_PROMPT_ACCEPTED, 1);
+}
+
+TEST_F(CardNameFixFlowControllerImplTest, LogUserAcceptedInferredName) {
+  base::HistogramTester histogram_tester;
+  ShowPromptWithInferredName();
+  AcceptWithInferredName();
+
+  histogram_tester.ExpectBucketCount("Autofill.SaveCardCardholderNameWasEdited",
+                                     false, 1);
+}
+
+TEST_F(CardNameFixFlowControllerImplTest, LogUserAcceptedEditedName) {
+  base::HistogramTester histogram_tester;
+  ShowPromptWithInferredName();
+  AcceptWithEditedName();
+
+  histogram_tester.ExpectBucketCount("Autofill.SaveCardCardholderNameWasEdited",
+                                     true, 1);
+}
+
+TEST_F(CardNameFixFlowControllerImplTest, LogDismissed) {
+  base::HistogramTester histogram_tester;
+  controller_->OnDismissed();
+
+  histogram_tester.ExpectBucketCount(
+      "Autofill.CardholderNameFixFlowPrompt.Events",
+      AutofillMetrics::CARDHOLDER_NAME_FIX_FLOW_PROMPT_DISMISSED, 1);
+}
+
+}  // namespace autofill
diff --git a/components/autofill/core/browser/ui/payments/card_name_fix_flow_view.h b/components/autofill/core/browser/ui/payments/card_name_fix_flow_view.h
new file mode 100644
index 0000000..f9bf6ce
--- /dev/null
+++ b/components/autofill/core/browser/ui/payments/card_name_fix_flow_view.h
@@ -0,0 +1,26 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_VIEW_H_
+#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_VIEW_H_
+
+#include "base/macros.h"
+#include "base/strings/string16.h"
+
+namespace autofill {
+
+// The cross-platform UI interface which prompts the user to confirm their name.
+// This object is responsible for its own lifetime.
+class CardNameFixFlowView {
+ public:
+  virtual void Show() = 0;
+  virtual void ControllerGone() = 0;
+
+ protected:
+  virtual ~CardNameFixFlowView() = default;
+};
+
+}  // namespace autofill
+
+#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_VIEW_H_
diff --git a/components/autofill/core/browser/ui/payments/card_name_fix_flow_view_delegate_mobile.cc b/components/autofill/core/browser/ui/payments/card_name_fix_flow_view_delegate_mobile.cc
deleted file mode 100644
index 94d6dc8..0000000
--- a/components/autofill/core/browser/ui/payments/card_name_fix_flow_view_delegate_mobile.cc
+++ /dev/null
@@ -1,82 +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 "components/autofill/core/browser/ui/payments/card_name_fix_flow_view_delegate_mobile.h"
-
-#include <utility>
-
-#include "base/logging.h"
-#include "base/strings/utf_string_conversions.h"
-#include "base/values.h"
-#include "build/branding_buildflags.h"
-#include "components/grit/components_scaled_resources.h"
-#include "components/strings/grit/components_strings.h"
-#include "ui/base/l10n/l10n_util.h"
-
-namespace autofill {
-
-CardNameFixFlowViewDelegateMobile::CardNameFixFlowViewDelegateMobile(
-    const base::string16& inferred_cardholder_name,
-    base::OnceCallback<void(const base::string16&)> upload_save_card_callback)
-    : inferred_cardholder_name_(inferred_cardholder_name),
-      upload_save_card_callback_(std::move(upload_save_card_callback)),
-      shown_(false),
-      had_user_interaction_(false) {
-  DCHECK(!upload_save_card_callback_.is_null());
-  AutofillMetrics::LogSaveCardCardholderNamePrefilled(
-      !inferred_cardholder_name_.empty());
-}
-
-CardNameFixFlowViewDelegateMobile::~CardNameFixFlowViewDelegateMobile() {
-  if (shown_ && !had_user_interaction_)
-    AutofillMetrics::LogCardholderNameFixFlowPromptEvent(
-        AutofillMetrics::
-            CARDHOLDER_NAME_FIX_FLOW_PROMPT_CLOSED_WITHOUT_INTERACTION);
-}
-
-int CardNameFixFlowViewDelegateMobile::GetIconId() const {
-#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
-  return IDR_AUTOFILL_GOOGLE_PAY_WITH_DIVIDER;
-#else
-  return 0;
-#endif
-}
-
-base::string16 CardNameFixFlowViewDelegateMobile::GetTitleText() const {
-  return l10n_util::GetStringUTF16(
-      IDS_AUTOFILL_SAVE_CARD_CARDHOLDER_NAME_FIX_FLOW_HEADER);
-}
-
-base::string16 CardNameFixFlowViewDelegateMobile::GetInferredCardHolderName()
-    const {
-  return inferred_cardholder_name_;
-}
-
-base::string16 CardNameFixFlowViewDelegateMobile::GetSaveButtonLabel() const {
-  return l10n_util::GetStringUTF16(
-      IDS_AUTOFILL_FIX_FLOW_PROMPT_SAVE_CARD_LABEL);
-}
-
-void CardNameFixFlowViewDelegateMobile::Accept(const base::string16& name) {
-  std::move(upload_save_card_callback_).Run(name);
-  AutofillMetrics::LogCardholderNameFixFlowPromptEvent(
-      AutofillMetrics::CARDHOLDER_NAME_FIX_FLOW_PROMPT_ACCEPTED);
-  had_user_interaction_ = true;
-  AutofillMetrics::LogSaveCardCardholderNameWasEdited(
-      inferred_cardholder_name_ != name);
-}
-
-void CardNameFixFlowViewDelegateMobile::Dismissed() {
-  AutofillMetrics::LogCardholderNameFixFlowPromptEvent(
-      AutofillMetrics::CARDHOLDER_NAME_FIX_FLOW_PROMPT_DISMISSED);
-  had_user_interaction_ = true;
-}
-
-void CardNameFixFlowViewDelegateMobile::Shown() {
-  AutofillMetrics::LogCardholderNameFixFlowPromptEvent(
-      AutofillMetrics::CARDHOLDER_NAME_FIX_FLOW_PROMPT_SHOWN);
-  shown_ = true;
-}
-
-}  // namespace autofill
diff --git a/components/autofill/core/browser/ui/payments/card_name_fix_flow_view_delegate_mobile.h b/components/autofill/core/browser/ui/payments/card_name_fix_flow_view_delegate_mobile.h
deleted file mode 100644
index 64415a4..0000000
--- a/components/autofill/core/browser/ui/payments/card_name_fix_flow_view_delegate_mobile.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_VIEW_DELEGATE_MOBILE_H_
-#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_VIEW_DELEGATE_MOBILE_H_
-
-#include <memory>
-
-#include "base/callback.h"
-#include "base/macros.h"
-#include "base/strings/string16.h"
-#include "components/autofill/core/browser/autofill_metrics.h"
-
-namespace autofill {
-
-// Enables the user to accept or deny cardholder name fix flow prompt.
-// Only used on mobile.
-class CardNameFixFlowViewDelegateMobile {
- public:
-  CardNameFixFlowViewDelegateMobile(
-      const base::string16& inferred_cardholder_name,
-      base::OnceCallback<void(const base::string16&)>
-          upload_save_card_callback);
-
-  ~CardNameFixFlowViewDelegateMobile();
-
-  int GetIconId() const;
-  base::string16 GetTitleText() const;
-  base::string16 GetInferredCardHolderName() const;
-  base::string16 GetSaveButtonLabel() const;
-  void Accept(const base::string16& name);
-  void Dismissed();
-  void Shown();
-
- private:
-  // Inferred cardholder name from Gaia account.
-  base::string16 inferred_cardholder_name_;
-
-  // The callback to save the credit card to Google Payments once user accepts
-  // fix flow.
-  base::OnceCallback<void(const base::string16&)> upload_save_card_callback_;
-
-  // Whether the prompt was shown to the user.
-  bool shown_;
-
-  // Did the user ever explicitly accept or dismiss this prompt?
-  bool had_user_interaction_;
-
-  DISALLOW_COPY_AND_ASSIGN(CardNameFixFlowViewDelegateMobile);
-};
-
-}  // namespace autofill
-
-#endif  // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_PAYMENTS_CARD_NAME_FIX_FLOW_VIEW_DELEGATE_MOBILE_H_
diff --git a/components/chromeos_camera/BUILD.gn b/components/chromeos_camera/BUILD.gn
index ed195d1..2b80eb9 100644
--- a/components/chromeos_camera/BUILD.gn
+++ b/components/chromeos_camera/BUILD.gn
@@ -242,14 +242,19 @@
     deps += [
       "//media/gpu/vaapi",
       "//media/gpu/vaapi:jpeg_decoder_unit_test",
-
-      # TODO(crbug.com/986074): we should move this to its own executable, but
-      # this would imply creating a new Tast wrapper in Chrome OS. So, for
-      # convenience, we make the WebP tests run with the
-      # jpeg_decode_accelerator_unittest binary.
-      "//media/gpu/vaapi:webp_decoder_unit_test",
     ]
 
+    # TODO(crbug.com/1008962): Build this on component builds as well.
+    if (!is_component_build) {
+      deps += [
+        # TODO(crbug.com/986074): we should move this to its own executable, but
+        # this would imply creating a new Tast wrapper in Chrome OS. So, for
+        # convenience, we make the WebP tests run with the
+        # jpeg_decode_accelerator_unittest binary.
+        "//media/gpu/vaapi:webp_decoder_unit_test",
+      ]
+    }
+
     data += [ "//media/test/data/pixel-1280x720.jpg" ]
   }
   if (use_x11) {
diff --git a/components/cronet/stale_host_resolver.cc b/components/cronet/stale_host_resolver.cc
index b1775cf..c9536aa 100644
--- a/components/cronet/stale_host_resolver.cc
+++ b/components/cronet/stale_host_resolver.cc
@@ -441,6 +441,10 @@
 
 StaleHostResolver::~StaleHostResolver() {}
 
+void StaleHostResolver::OnShutdown() {
+  inner_resolver_->OnShutdown();
+}
+
 std::unique_ptr<net::HostResolver::ResolveHostRequest>
 StaleHostResolver::CreateRequest(
     const net::HostPortPair& host,
diff --git a/components/cronet/stale_host_resolver.h b/components/cronet/stale_host_resolver.h
index a292dc31..04e2046 100644
--- a/components/cronet/stale_host_resolver.h
+++ b/components/cronet/stale_host_resolver.h
@@ -70,6 +70,8 @@
 
   // HostResolver implementation:
 
+  void OnShutdown() override;
+
   // Resolves as a regular HostResolver, but if stale data is available and
   // usable (according to the options passed to the constructor), and fresh data
   // is not returned before the specified delay, returns the stale data instead.
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
index 3328eec98..f2079cc 100644
--- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_settings_unittest.cc
@@ -179,14 +179,13 @@
     drp_test_context->SetDataReductionProxyEnabled(true);
     drp_test_context->RunUntilIdle();
 
-    network::ResourceResponseHead resource_response_head;
+    auto url_response_head = network::mojom::URLResponseHead::New();
     std::string headers(test_case.response_headers);
-    resource_response_head.headers =
-        base::MakeRefCounted<net::HttpResponseHeaders>(
-            net::HttpUtil::AssembleRawHeaders(headers));
+    url_response_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+        net::HttpUtil::AssembleRawHeaders(headers));
     test_url_loader_factory.SimulateResponseWithoutRemovingFromPendingList(
-        test_url_loader_factory.GetPendingRequest(0), resource_response_head,
-        test_case.response_body,
+        test_url_loader_factory.GetPendingRequest(0),
+        std::move(url_response_head), test_case.response_body,
         network::URLLoaderCompletionStatus(test_case.net_error_code));
 
     if (test_case.expected_restricted) {
diff --git a/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc b/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc
index 843f7b3..514ad57 100644
--- a/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc
+++ b/components/data_reduction_proxy/core/browser/warmup_url_fetcher_unittest.cc
@@ -169,12 +169,12 @@
   EXPECT_TRUE(warmup_url_fetcher.IsFetchInFlight());
   task_environment.RunUntilIdle();
 
-  auto resource_response_head =
-      network::CreateResourceResponseHead(net::HTTP_OK);
-  resource_response_head.proxy_server = proxy_server;
+  auto url_response_head = network::CreateURLResponseHead(net::HTTP_OK);
+  url_response_head->proxy_server = proxy_server;
   test_url_loader_factory.SimulateResponseWithoutRemovingFromPendingList(
-      test_url_loader_factory.GetPendingRequest(0), resource_response_head,
-      "foobarbaz", network::URLLoaderCompletionStatus(net::OK));
+      test_url_loader_factory.GetPendingRequest(0),
+      std::move(url_response_head), "foobarbaz",
+      network::URLLoaderCompletionStatus(net::OK));
 
   EXPECT_FALSE(warmup_url_fetcher.IsFetchInFlight());
 
@@ -215,15 +215,15 @@
   EXPECT_TRUE(warmup_url_fetcher.IsFetchInFlight());
   task_environment.RunUntilIdle();
 
-  auto resource_response_head =
-      network::CreateResourceResponseHead(net::HTTP_NOT_FOUND);
-  resource_response_head.proxy_server = proxy_server;
+  auto url_response_head = network::CreateURLResponseHead(net::HTTP_NOT_FOUND);
+  url_response_head->proxy_server = proxy_server;
   static const char kDataReductionProxyViaValue[] =
       "Via: 1.1 Chrome-Compression-Proxy";
-  resource_response_head.headers->AddHeader(kDataReductionProxyViaValue);
+  url_response_head->headers->AddHeader(kDataReductionProxyViaValue);
   test_url_loader_factory.SimulateResponseWithoutRemovingFromPendingList(
-      test_url_loader_factory.GetPendingRequest(0), resource_response_head,
-      "foobarbaz", network::URLLoaderCompletionStatus(net::OK));
+      test_url_loader_factory.GetPendingRequest(0),
+      std::move(url_response_head), "foobarbaz",
+      network::URLLoaderCompletionStatus(net::OK));
 
   EXPECT_FALSE(warmup_url_fetcher.IsFetchInFlight());
 
@@ -265,15 +265,15 @@
   warmup_url_fetcher.FetchWarmupURL(0, DataReductionProxyServer(proxy_server));
   base::RunLoop().RunUntilIdle();
 
-  auto resource_response_head =
-      network::CreateResourceResponseHead(net::HTTP_NO_CONTENT);
-  resource_response_head.proxy_server = proxy_server;
+  auto url_response_head = network::CreateURLResponseHead(net::HTTP_NO_CONTENT);
+  url_response_head->proxy_server = proxy_server;
   static const char kDataReductionProxyViaValue[] =
       "Via: 1.1 Chrome-Compression-Proxy";
-  resource_response_head.headers->AddHeader(kDataReductionProxyViaValue);
+  url_response_head->headers->AddHeader(kDataReductionProxyViaValue);
   test_url_loader_factory.SimulateResponseWithoutRemovingFromPendingList(
-      test_url_loader_factory.GetPendingRequest(0), resource_response_head,
-      "foobarbaz", network::URLLoaderCompletionStatus(net::OK));
+      test_url_loader_factory.GetPendingRequest(0),
+      std::move(url_response_head), "foobarbaz",
+      network::URLLoaderCompletionStatus(net::OK));
 
   histogram_tester.ExpectUniqueSample(
       "DataReductionProxy.WarmupURL.FetchInitiated", 1, 1);
@@ -309,7 +309,7 @@
 
   test_url_loader_factory.SimulateResponseWithoutRemovingFromPendingList(
       test_url_loader_factory.GetPendingRequest(0),
-      network::ResourceResponseHead(), "foobarbaz",
+      network::mojom::URLResponseHead::New(), "foobarbaz",
       network::URLLoaderCompletionStatus(net::ERR_CONNECTION_RESET));
 
   EXPECT_FALSE(warmup_url_fetcher.IsFetchInFlight());
@@ -385,15 +385,15 @@
   warmup_url_fetcher.FetchWarmupURL(1, DataReductionProxyServer(proxy_server));
   task_environment.FastForwardBy(base::TimeDelta::FromMilliseconds(2));
 
-  auto resource_response_head =
-      network::CreateResourceResponseHead(net::HTTP_NOT_FOUND);
-  resource_response_head.proxy_server = proxy_server;
+  auto url_response_head = network::CreateURLResponseHead(net::HTTP_NOT_FOUND);
+  url_response_head->proxy_server = proxy_server;
   static const char kDataReductionProxyViaValue[] =
       "Via: 1.1 Chrome-Compression-Proxy";
-  resource_response_head.headers->AddHeader(kDataReductionProxyViaValue);
+  url_response_head->headers->AddHeader(kDataReductionProxyViaValue);
   test_url_loader_factory.SimulateResponseWithoutRemovingFromPendingList(
-      test_url_loader_factory.GetPendingRequest(0), resource_response_head,
-      "foobarbaz", network::URLLoaderCompletionStatus(net::OK));
+      test_url_loader_factory.GetPendingRequest(0),
+      std::move(url_response_head), "foobarbaz",
+      network::URLLoaderCompletionStatus(net::OK));
 
   EXPECT_FALSE(warmup_url_fetcher.IsFetchInFlight());
   base::RunLoop().RunUntilIdle();
diff --git a/components/dom_distiller/core/BUILD.gn b/components/dom_distiller/core/BUILD.gn
index 4f1315a5..215a030 100644
--- a/components/dom_distiller/core/BUILD.gn
+++ b/components/dom_distiller/core/BUILD.gn
@@ -28,7 +28,6 @@
     "dom_distiller_features.h",
     "dom_distiller_model.cc",
     "dom_distiller_model.h",
-    "dom_distiller_observer.h",
     "dom_distiller_request_view_base.cc",
     "dom_distiller_request_view_base.h",
     "dom_distiller_service.cc",
diff --git a/components/dom_distiller/core/distiller_url_fetcher_unittest.cc b/components/dom_distiller/core/distiller_url_fetcher_unittest.cc
index 93167b4..224c863 100644
--- a/components/dom_distiller/core/distiller_url_fetcher_unittest.cc
+++ b/components/dom_distiller/core/distiller_url_fetcher_unittest.cc
@@ -38,7 +38,7 @@
         std::string(kTestPageAResponse, sizeof(kTestPageAResponse)));
     test_url_loader_factory_.AddResponse(
         GURL(kTestPageB),
-        network::CreateResourceResponseHead(net::HTTP_INTERNAL_SERVER_ERROR),
+        network::CreateURLResponseHead(net::HTTP_INTERNAL_SERVER_ERROR),
         std::string(kTestPageBResponse, sizeof(kTestPageBResponse)),
         network::URLLoaderCompletionStatus(net::OK));
   }
diff --git a/components/dom_distiller/core/dom_distiller_observer.h b/components/dom_distiller/core/dom_distiller_observer.h
deleted file mode 100644
index 2c934149..0000000
--- a/components/dom_distiller/core/dom_distiller_observer.h
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef COMPONENTS_DOM_DISTILLER_CORE_DOM_DISTILLER_OBSERVER_H_
-#define COMPONENTS_DOM_DISTILLER_CORE_DOM_DISTILLER_OBSERVER_H_
-
-#include <string>
-#include <vector>
-
-#include "base/macros.h"
-#include "components/dom_distiller/core/article_entry.h"
-
-namespace dom_distiller {
-
-// Provides notifications for any mutations to entries of the reading list.
-class DomDistillerObserver {
- public:
-  // An update to an article entry.
-  struct ArticleUpdate {
-    enum UpdateType { ADD, UPDATE, REMOVE };
-    std::string entry_id;
-    UpdateType update_type;
-  };
-
-  virtual void ArticleEntriesUpdated(
-      const std::vector<ArticleUpdate>& updates) = 0;
-
- protected:
-  DomDistillerObserver() {}
-  virtual ~DomDistillerObserver() {}
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(DomDistillerObserver);
-};
-
-}  // namespace dom_distiller
-
-#endif  // COMPONENTS_DOM_DISTILLER_CORE_DOM_DISTILLER_OBSERVER_H_
diff --git a/components/dom_distiller/core/dom_distiller_service.cc b/components/dom_distiller/core/dom_distiller_service.cc
index 0685d3a..8ed1cee 100644
--- a/components/dom_distiller/core/dom_distiller_service.cc
+++ b/components/dom_distiller/core/dom_distiller_service.cc
@@ -272,20 +272,6 @@
   }
 }
 
-void DomDistillerService::AddObserver(DomDistillerObserver* observer) {
-  DCHECK(observer);
-  if (store_) {
-    store_->AddObserver(observer);
-  }
-}
-
-void DomDistillerService::RemoveObserver(DomDistillerObserver* observer) {
-  DCHECK(observer);
-  if (store_) {
-    store_->RemoveObserver(observer);
-  }
-}
-
 DistilledPagePrefs* DomDistillerService::GetDistilledPagePrefs() {
   return distilled_page_prefs_.get();
 }
diff --git a/components/dom_distiller/core/dom_distiller_service.h b/components/dom_distiller/core/dom_distiller_service.h
index a7677072..59d8e51 100644
--- a/components/dom_distiller/core/dom_distiller_service.h
+++ b/components/dom_distiller/core/dom_distiller_service.h
@@ -24,7 +24,6 @@
 class DistilledContentStore;
 class DistillerFactory;
 class DistillerPageFactory;
-class DomDistillerObserver;
 class DomDistillerStoreInterface;
 class TaskTracker;
 class ViewerHandle;
@@ -92,9 +91,6 @@
   virtual std::unique_ptr<DistillerPage> CreateDefaultDistillerPageWithHandle(
       std::unique_ptr<SourcePageHandle> handle) = 0;
 
-  virtual void AddObserver(DomDistillerObserver* observer) = 0;
-  virtual void RemoveObserver(DomDistillerObserver* observer) = 0;
-
   // Returns the DistilledPagePrefs owned by the instance of
   // DomDistillerService.
   virtual DistilledPagePrefs* GetDistilledPagePrefs() = 0;
@@ -138,8 +134,6 @@
       const gfx::Size& render_view_size) override;
   std::unique_ptr<DistillerPage> CreateDefaultDistillerPageWithHandle(
       std::unique_ptr<SourcePageHandle> handle) override;
-  void AddObserver(DomDistillerObserver* observer) override;
-  void RemoveObserver(DomDistillerObserver* observer) override;
   DistilledPagePrefs* GetDistilledPagePrefs() override;
 
  private:
diff --git a/components/dom_distiller/core/dom_distiller_service_unittest.cc b/components/dom_distiller/core/dom_distiller_service_unittest.cc
index e20cb06..d2590e3 100644
--- a/components/dom_distiller/core/dom_distiller_service_unittest.cc
+++ b/components/dom_distiller/core/dom_distiller_service_unittest.cc
@@ -41,12 +41,6 @@
                void(ArticleDistillationUpdate article_update));
 };
 
-class MockDistillerObserver : public DomDistillerObserver {
- public:
-  MOCK_METHOD1(ArticleEntriesUpdated, void(const std::vector<ArticleUpdate>&));
-  ~MockDistillerObserver() override {}
-};
-
 class MockArticleAvailableCallback {
  public:
   MOCK_METHOD1(DistillationCompleted, void(bool));
@@ -271,8 +265,6 @@
 
 TEST_F(DomDistillerServiceTest, TestCancellation) {
   FakeDistiller* distiller = new FakeDistiller(false);
-  MockDistillerObserver observer;
-  service_->AddObserver(&observer);
 
   EXPECT_CALL(*distiller_factory_, CreateDistillerImpl())
       .WillOnce(Return(distiller));
@@ -290,50 +282,6 @@
   base::RunLoop().RunUntilIdle();
 }
 
-TEST_F(DomDistillerServiceTest, TestMultipleObservers) {
-  FakeDistiller* distiller = new FakeDistiller(false);
-  EXPECT_CALL(*distiller_factory_, CreateDistillerImpl())
-      .WillOnce(Return(distiller));
-
-  const int kObserverCount = 5;
-  MockDistillerObserver observers[kObserverCount];
-  for (int i = 0; i < kObserverCount; ++i) {
-    service_->AddObserver(&observers[i]);
-  }
-
-  DomDistillerService::ArticleAvailableCallback article_cb;
-  GURL url("http://www.example.com/p1");
-  std::string entry_id = service_->AddToList(
-      url, service_->CreateDefaultDistillerPage(gfx::Size()), article_cb);
-
-  // Distillation should notify all observers that article is added.
-  std::vector<DomDistillerObserver::ArticleUpdate> expected_updates;
-  DomDistillerObserver::ArticleUpdate update;
-  update.entry_id = entry_id;
-  update.update_type = DomDistillerObserver::ArticleUpdate::ADD;
-  expected_updates.push_back(update);
-
-  for (int i = 0; i < kObserverCount; ++i) {
-    EXPECT_CALL(observers[i], ArticleEntriesUpdated(
-                                  util::HasExpectedUpdates(expected_updates)));
-  }
-
-  std::unique_ptr<DistilledArticleProto> proto = CreateDefaultArticle();
-  RunDistillerCallback(distiller, std::move(proto));
-
-  // Remove should notify all observers that article is removed.
-  update.update_type = DomDistillerObserver::ArticleUpdate::REMOVE;
-  expected_updates.clear();
-  expected_updates.push_back(update);
-  for (int i = 0; i < kObserverCount; ++i) {
-    EXPECT_CALL(observers[i], ArticleEntriesUpdated(
-                                  util::HasExpectedUpdates(expected_updates)));
-  }
-
-  service_->RemoveEntry(entry_id);
-  base::RunLoop().RunUntilIdle();
-}
-
 TEST_F(DomDistillerServiceTest, TestMultipleCallbacks) {
   FakeDistiller* distiller = new FakeDistiller(false);
   EXPECT_CALL(*distiller_factory_, CreateDistillerImpl())
diff --git a/components/dom_distiller/core/dom_distiller_store.cc b/components/dom_distiller/core/dom_distiller_store.cc
index 2cd9dce..826ee22 100644
--- a/components/dom_distiller/core/dom_distiller_store.cc
+++ b/components/dom_distiller/core/dom_distiller_store.cc
@@ -100,53 +100,14 @@
   return true;
 }
 
-void DomDistillerStore::AddObserver(DomDistillerObserver* observer) {
-  observers_.AddObserver(observer);
-}
-
-void DomDistillerStore::RemoveObserver(DomDistillerObserver* observer) {
-  observers_.RemoveObserver(observer);
-}
-
 std::vector<ArticleEntry> DomDistillerStore::GetEntries() const {
   return model_.GetEntries();
 }
 
-void DomDistillerStore::NotifyObservers(const syncer::SyncChangeList& changes) {
-  if (observers_.might_have_observers() && changes.size() > 0) {
-    std::vector<DomDistillerObserver::ArticleUpdate> article_changes;
-    for (auto it = changes.begin(); it != changes.end(); ++it) {
-      DomDistillerObserver::ArticleUpdate article_update;
-      switch (it->change_type()) {
-        case SyncChange::ACTION_ADD:
-          article_update.update_type = DomDistillerObserver::ArticleUpdate::ADD;
-          break;
-        case SyncChange::ACTION_UPDATE:
-          article_update.update_type =
-              DomDistillerObserver::ArticleUpdate::UPDATE;
-          break;
-        case SyncChange::ACTION_DELETE:
-          article_update.update_type =
-              DomDistillerObserver::ArticleUpdate::REMOVE;
-          break;
-        case SyncChange::ACTION_INVALID:
-          NOTREACHED();
-          break;
-      }
-      const ArticleEntry& entry = GetEntryFromChange(*it);
-      article_update.entry_id = entry.entry_id();
-      article_changes.push_back(article_update);
-    }
-    for (DomDistillerObserver& observer : observers_)
-      observer.ArticleEntriesUpdated(article_changes);
-  }
-}
-
 void DomDistillerStore::ApplyChangesToModel(const SyncChangeList& changes,
                                             SyncChangeList* changes_applied,
                                             SyncChangeList* changes_missing) {
   model_.ApplyChangesToModel(changes, changes_applied, changes_missing);
-  NotifyObservers(*changes_applied);
 }
 
 void DomDistillerStore::OnDatabaseInit(
diff --git a/components/dom_distiller/core/dom_distiller_store.h b/components/dom_distiller/core/dom_distiller_store.h
index ae2ac1f..1153ee9b 100644
--- a/components/dom_distiller/core/dom_distiller_store.h
+++ b/components/dom_distiller/core/dom_distiller_store.h
@@ -10,10 +10,8 @@
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
-#include "base/observer_list.h"
 #include "components/dom_distiller/core/article_entry.h"
 #include "components/dom_distiller/core/dom_distiller_model.h"
-#include "components/dom_distiller/core/dom_distiller_observer.h"
 #include "components/leveldb_proto/public/proto_database.h"
 #include "components/sync/model/sync_change.h"
 #include "components/sync/model/sync_data.h"
@@ -39,10 +37,6 @@
 
   // Gets a copy of all the current entries.
   virtual std::vector<ArticleEntry> GetEntries() const = 0;
-
-  virtual void AddObserver(DomDistillerObserver* observer) = 0;
-
-  virtual void RemoveObserver(DomDistillerObserver* observer) = 0;
 };
 
 // Implements syncing/storing of DomDistiller entries. This keeps three
@@ -84,9 +78,6 @@
   bool GetEntryByUrl(const GURL& url, ArticleEntry* entry) override;
   std::vector<ArticleEntry> GetEntries() const override;
 
-  void AddObserver(DomDistillerObserver* observer) override;
-  void RemoveObserver(DomDistillerObserver* observer) override;
-
  private:
   void OnDatabaseInit(leveldb_proto::Enums::InitStatus status);
   void OnDatabaseLoad(bool success, std::unique_ptr<EntryVector> entries);
@@ -108,11 +99,8 @@
                            syncer::SyncChangeList* changes_applied,
                            syncer::SyncChangeList* changes_missing);
 
-  void NotifyObservers(const syncer::SyncChangeList& changes);
-
   std::unique_ptr<leveldb_proto::ProtoDatabase<ArticleEntry>> database_;
   bool database_loaded_;
-  base::ObserverList<DomDistillerObserver>::Unchecked observers_;
 
   DomDistillerModel model_;
 
diff --git a/components/dom_distiller/core/dom_distiller_store_unittest.cc b/components/dom_distiller/core/dom_distiller_store_unittest.cc
index 32db73b..ad601489 100644
--- a/components/dom_distiller/core/dom_distiller_store_unittest.cc
+++ b/components/dom_distiller/core/dom_distiller_store_unittest.cc
@@ -77,12 +77,6 @@
   return entries[id % 9];
 }
 
-class MockDistillerObserver : public DomDistillerObserver {
- public:
-  MOCK_METHOD1(ArticleEntriesUpdated, void(const std::vector<ArticleUpdate>&));
-  ~MockDistillerObserver() override {}
-};
-
 }  // namespace
 
 class DomDistillerStoreTest : public testing::Test {
@@ -234,37 +228,4 @@
   EXPECT_FALSE(store_->UpdateEntry(GetSampleEntry(0)));
 }
 
-TEST_F(DomDistillerStoreTest, TestObserver) {
-  CreateStore();
-  MockDistillerObserver observer;
-  store_->AddObserver(&observer);
-  fake_db_->InitStatusCallback(leveldb_proto::Enums::InitStatus::kOK);
-  fake_db_->LoadCallback(true);
-  std::vector<DomDistillerObserver::ArticleUpdate> expected_updates;
-  DomDistillerObserver::ArticleUpdate update;
-  update.entry_id = GetSampleEntry(0).entry_id();
-  update.update_type = DomDistillerObserver::ArticleUpdate::ADD;
-  expected_updates.push_back(update);
-  EXPECT_CALL(observer, ArticleEntriesUpdated(
-                            test::util::HasExpectedUpdates(expected_updates)));
-  store_->AddEntry(GetSampleEntry(0));
-
-  expected_updates.clear();
-  update.entry_id = GetSampleEntry(1).entry_id();
-  update.update_type = DomDistillerObserver::ArticleUpdate::ADD;
-  expected_updates.push_back(update);
-  EXPECT_CALL(observer, ArticleEntriesUpdated(
-                            test::util::HasExpectedUpdates(expected_updates)));
-  store_->AddEntry(GetSampleEntry(1));
-
-  expected_updates.clear();
-  update.entry_id = GetSampleEntry(0).entry_id();
-  update.update_type = DomDistillerObserver::ArticleUpdate::REMOVE;
-  expected_updates.clear();
-  expected_updates.push_back(update);
-  EXPECT_CALL(observer, ArticleEntriesUpdated(
-                            test::util::HasExpectedUpdates(expected_updates)));
-  store_->RemoveEntry(GetSampleEntry(0));
-}
-
 }  // namespace dom_distiller
diff --git a/components/dom_distiller/core/dom_distiller_test_util.cc b/components/dom_distiller/core/dom_distiller_test_util.cc
index 52c77c3..83199cd 100644
--- a/components/dom_distiller/core/dom_distiller_test_util.cc
+++ b/components/dom_distiller/core/dom_distiller_test_util.cc
@@ -25,67 +25,6 @@
 }
 }  // namespace
 
-ObserverUpdatesMatcher::ObserverUpdatesMatcher(
-    const std::vector<DomDistillerObserver::ArticleUpdate>& expected_updates)
-    : expected_updates_(expected_updates) {}
-
-bool ObserverUpdatesMatcher::MatchAndExplain(
-    const std::vector<DomDistillerObserver::ArticleUpdate>& actual_updates,
-    testing::MatchResultListener* listener) const {
-  if (actual_updates.size() != expected_updates_.size()) {
-    *listener << "Incorrect number of updates. Expected: "
-              << expected_updates_.size() << " got: " << actual_updates.size();
-    return false;
-  }
-  std::vector<DomDistillerObserver::ArticleUpdate>::const_iterator expected,
-      actual;
-  for (expected = expected_updates_.begin(), actual = actual_updates.begin();
-       expected != expected_updates_.end(); ++expected, ++actual) {
-    if (expected->entry_id != actual->entry_id) {
-      *listener << " Mismatched entry id. Expected: " << expected->entry_id
-                << " actual: " << actual->entry_id;
-      return false;
-    }
-    if (expected->update_type != actual->update_type) {
-      *listener << " Mismatched update for entryid:" << expected->entry_id
-                << ". Expected: " << expected->update_type
-                << " actual: " << actual->update_type;
-      return false;
-    }
-  }
-  return true;
-}
-
-void ObserverUpdatesMatcher::DescribeUpdates(std::ostream* os) const {
-  bool start = true;
-  for (auto i = expected_updates_.begin(); i != expected_updates_.end(); ++i) {
-    if (start) {
-      start = false;
-    } else {
-      *os << ", ";
-    }
-    *os << "( EntryId: " << i->entry_id << ", UpdateType: " << i->update_type
-        << " )";
-  }
-}
-
-void ObserverUpdatesMatcher::DescribeTo(std::ostream* os) const {
-  *os << " has updates: { ";
-  DescribeUpdates(os);
-  *os << "}";
-}
-void ObserverUpdatesMatcher::DescribeNegationTo(std::ostream* os) const {
-  *os << " does not have updates: { ";
-  DescribeUpdates(os);
-  *os << "}";
-}
-
-testing::Matcher<const std::vector<DomDistillerObserver::ArticleUpdate>&>
-HasExpectedUpdates(
-    const std::vector<DomDistillerObserver::ArticleUpdate>& expected_updates) {
-  return testing::MakeMatcher(new ObserverUpdatesMatcher(expected_updates));
-}
-
 // static
 DomDistillerStore* CreateStoreWithFakeDB(
     FakeDB<ArticleEntry>* fake_db,
diff --git a/components/dom_distiller/core/dom_distiller_test_util.h b/components/dom_distiller/core/dom_distiller_test_util.h
index 93cdca9..4c94a93 100644
--- a/components/dom_distiller/core/dom_distiller_test_util.h
+++ b/components/dom_distiller/core/dom_distiller_test_util.h
@@ -7,7 +7,7 @@
 
 #include <vector>
 
-#include "components/dom_distiller/core/dom_distiller_observer.h"
+#include "components/dom_distiller/core/article_entry.h"
 #include "components/leveldb_proto/testing/fake_db.h"
 #include "testing/gmock/include/gmock/gmock.h"
 
@@ -18,28 +18,6 @@
 namespace test {
 namespace util {
 
-class ObserverUpdatesMatcher
-    : public testing::MatcherInterface<
-          const std::vector<DomDistillerObserver::ArticleUpdate>&> {
- public:
-  explicit ObserverUpdatesMatcher(
-      const std::vector<DomDistillerObserver::ArticleUpdate>&);
-
-  // MatcherInterface overrides.
-  bool MatchAndExplain(
-      const std::vector<DomDistillerObserver::ArticleUpdate>& actual_updates,
-      testing::MatchResultListener* listener) const override;
-  void DescribeTo(std::ostream* os) const override;
-  void DescribeNegationTo(std::ostream* os) const override;
-
- private:
-  void DescribeUpdates(std::ostream* os) const;
-  const std::vector<DomDistillerObserver::ArticleUpdate>& expected_updates_;
-};
-
-testing::Matcher<const std::vector<DomDistillerObserver::ArticleUpdate>&>
-HasExpectedUpdates(const std::vector<DomDistillerObserver::ArticleUpdate>&);
-
 // Creates a simple DomDistillerStore backed by |fake_db| and initialized
 // with |store_model|.
 DomDistillerStore* CreateStoreWithFakeDB(
diff --git a/components/dom_distiller/core/viewer_unittest.cc b/components/dom_distiller/core/viewer_unittest.cc
index 493daad..2283843 100644
--- a/components/dom_distiller/core/viewer_unittest.cc
+++ b/components/dom_distiller/core/viewer_unittest.cc
@@ -54,8 +54,6 @@
   MOCK_METHOD1(HasEntry, bool(const std::string&));
   MOCK_METHOD1(GetUrlForEntry, std::string(const std::string&));
   MOCK_CONST_METHOD0(GetEntries, std::vector<ArticleEntry>());
-  MOCK_METHOD1(AddObserver, void(DomDistillerObserver*));
-  MOCK_METHOD1(RemoveObserver, void(DomDistillerObserver*));
   MOCK_METHOD0(ViewUrlImpl, ViewerHandle*());
   std::unique_ptr<ViewerHandle> ViewUrl(
       ViewRequestDelegate*,
diff --git a/components/download/internal/background_service/in_memory_download_unittest.cc b/components/download/internal/background_service/in_memory_download_unittest.cc
index 5c4b9dff..daeba85 100644
--- a/components/download/internal/background_service/in_memory_download_unittest.cc
+++ b/components/download/internal/background_service/in_memory_download_unittest.cc
@@ -210,27 +210,28 @@
   // Add a redirect.
   net::RedirectInfo redirect_info;
   redirect_info.new_url = GURL("https://example.com/redirect12345");
-  network::TestURLLoaderFactory::Redirects redirects = {
-      {redirect_info, network::ResourceResponseHead()}};
+  network::TestURLLoaderFactory::Redirects redirects;
+  redirects.push_back({redirect_info, network::mojom::URLResponseHead::New()});
 
   // Add some random header.
-  network::ResourceResponseHead response_head;
-  response_head.headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
-  response_head.headers->AddHeader("X-Random-Test-Header: 123");
+  auto response_head = network::mojom::URLResponseHead::New();
+  response_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>("");
+  response_head->headers->AddHeader("X-Random-Test-Header: 123");
 
   // The size must match for download as stream from SimpleUrlLoader.
   network::URLLoaderCompletionStatus status;
   status.decoded_body_length = base::size(kTestDownloadData) - 1;
 
-  url_loader_factory()->AddResponse(request_params.url, response_head,
-                                    kTestDownloadData, status, redirects);
+  url_loader_factory()->AddResponse(request_params.url, response_head.Clone(),
+                                    kTestDownloadData, status,
+                                    std::move(redirects));
 
   std::vector<GURL> expected_url_chain = {request_params.url,
                                           redirect_info.new_url};
 
   EXPECT_CALL(*delegate(),
               OnDownloadStarted(InMemoryDownloadMatcher(
-                  response_head.headers->raw_headers(), expected_url_chain)));
+                  response_head->headers->raw_headers(), expected_url_chain)));
 
   download()->Start();
   delegate()->WaitForCompletion();
@@ -240,7 +241,7 @@
   // the original URL and redirect URL, and should not contain the final URL.
   EXPECT_EQ(download()->url_chain(), expected_url_chain);
   EXPECT_EQ(download()->response_headers()->raw_headers(),
-            response_head.headers->raw_headers());
+            response_head->headers->raw_headers());
 
   // Verfiy the data persisted to disk after redirect chain.
   auto blob = download()->ResultAsBlob();
diff --git a/components/feed/OWNERS b/components/feed/OWNERS
index 2efa28a..0cce6ad 100644
--- a/components/feed/OWNERS
+++ b/components/feed/OWNERS
@@ -1,8 +1,7 @@
+carlosk@chromium.org
 fgorski@chromium.org
-pavely@chromium.org
-pnoland@chromium.org
+harringtond@chromium.org
 skym@chromium.org
-zea@chromium.org
 
-# Team: chrome-jardin-team@google.com
+# Team: feed@chromium.org
 # COMPONENT: UI>Browser>ContentSuggestions>Feed
diff --git a/components/feed/core/feed_networking_host_unittest.cc b/components/feed/core/feed_networking_host_unittest.cc
index d29f177e..4bd71f4 100644
--- a/components/feed/core/feed_networking_host_unittest.cc
+++ b/components/feed/core/feed_networking_host_unittest.cc
@@ -86,14 +86,14 @@
                net::HttpStatusCode code = net::HTTP_OK,
                network::URLLoaderCompletionStatus status =
                    network::URLLoaderCompletionStatus()) {
-    network::ResourceResponseHead head;
+    auto head = network::mojom::URLResponseHead::New();
     if (code >= 0) {
-      head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+      head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
           "HTTP/1.1 " + base::NumberToString(code));
       status.decoded_body_length = response_string.length();
     }
 
-    test_factory_.AddResponse(url, head, response_string, status);
+    test_factory_.AddResponse(url, std::move(head), response_string, status);
 
     task_environment_.FastForwardUntilNoTasksRemain();
   }
diff --git a/components/feedback/feedback_uploader_dispatch_unittest.cc b/components/feedback/feedback_uploader_dispatch_unittest.cc
index 8830c7c4..9096a0e 100644
--- a/components/feedback/feedback_uploader_dispatch_unittest.cc
+++ b/components/feedback/feedback_uploader_dispatch_unittest.cc
@@ -116,13 +116,13 @@
   EXPECT_EQ(kTestRetryDelay, uploader.retry_delay());
   // Successful reports should not introduce any retries, and should not
   // increase the backoff delay.
-  network::ResourceResponseHead head;
+  auto head = network::mojom::URLResponseHead::New();
   std::string headers("HTTP/1.1 204 No Content\n\n");
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
       net::HttpUtil::AssembleRawHeaders(headers));
   network::URLLoaderCompletionStatus status;
-  test_url_loader_factory()->AddResponse(GURL(kFeedbackPostUrl), head, "",
-                                         status);
+  test_url_loader_factory()->AddResponse(GURL(kFeedbackPostUrl),
+                                         std::move(head), "", status);
   QueueReport(&uploader, "Successful report");
   base::RunLoop().RunUntilIdle();
 
@@ -139,13 +139,13 @@
   EXPECT_EQ(kTestRetryDelay, uploader.retry_delay());
   // Failed reports due to client errors are not retried. No backoff delay
   // should be doubled.
-  network::ResourceResponseHead head;
+  auto head = network::mojom::URLResponseHead::New();
   std::string headers("HTTP/1.1 400 Bad Request\n\n");
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
       net::HttpUtil::AssembleRawHeaders(headers));
   network::URLLoaderCompletionStatus status;
-  test_url_loader_factory()->AddResponse(GURL(kFeedbackPostUrl), head, "",
-                                         status);
+  test_url_loader_factory()->AddResponse(GURL(kFeedbackPostUrl),
+                                         std::move(head), "", status);
   QueueReport(&uploader, "Client error failed report");
   base::RunLoop().RunUntilIdle();
 
@@ -161,13 +161,13 @@
 
   EXPECT_EQ(kTestRetryDelay, uploader.retry_delay());
   // Failed reports due to server errors are retried.
-  network::ResourceResponseHead head;
+  auto head = network::mojom::URLResponseHead::New();
   std::string headers("HTTP/1.1 500 Server Error\n\n");
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
       net::HttpUtil::AssembleRawHeaders(headers));
   network::URLLoaderCompletionStatus status;
-  test_url_loader_factory()->AddResponse(GURL(kFeedbackPostUrl), head, "",
-                                         status);
+  test_url_loader_factory()->AddResponse(GURL(kFeedbackPostUrl),
+                                         std::move(head), "", status);
   QueueReport(&uploader, "Server error failed report");
   base::RunLoop().RunUntilIdle();
 
diff --git a/components/gcm_driver/account_tracker_unittest.cc b/components/gcm_driver/account_tracker_unittest.cc
index 8a6ddc9b..0e20908 100644
--- a/components/gcm_driver/account_tracker_unittest.cc
+++ b/components/gcm_driver/account_tracker_unittest.cc
@@ -345,7 +345,7 @@
     const std::string& response_string) {
   EXPECT_TRUE(test_url_loader_factory()->SimulateResponseForPendingRequest(
       GURL(kOAuthURL), network::URLLoaderCompletionStatus(net::OK),
-      network::CreateResourceResponseHead(response_code), response_string));
+      network::CreateURLResponseHead(response_code), response_string));
 }
 
 void AccountTrackerTest::ReturnOAuthUrlFetchSuccess(
diff --git a/components/gcm_driver/gcm_account_tracker_unittest.cc b/components/gcm_driver/gcm_account_tracker_unittest.cc
index 064a16c..f3b7cf8 100644
--- a/components/gcm_driver/gcm_account_tracker_unittest.cc
+++ b/components/gcm_driver/gcm_account_tracker_unittest.cc
@@ -251,7 +251,7 @@
   EXPECT_TRUE(test_url_loader_factory()->IsPending(kOAuthURL));
   test_url_loader_factory()->SimulateResponseForPendingRequest(
       GURL(kOAuthURL), network::URLLoaderCompletionStatus(net::OK),
-      network::CreateResourceResponseHead(net::HTTP_OK),
+      network::CreateURLResponseHead(net::HTTP_OK),
       GetValidTokenInfoResponse(account_id));
 
   GetValidTokenInfoResponse(account_id);
diff --git a/components/gcm_driver/gcm_client_impl_unittest.cc b/components/gcm_driver/gcm_client_impl_unittest.cc
index c1c7777..f3f29ed 100644
--- a/components/gcm_driver/gcm_client_impl_unittest.cc
+++ b/components/gcm_driver/gcm_client_impl_unittest.cc
@@ -558,7 +558,7 @@
   EXPECT_TRUE(url_loader_factory()->SimulateResponseForPendingRequest(
       gservices_settings().GetCheckinURL(),
       network::URLLoaderCompletionStatus(net::OK),
-      network::CreateResourceResponseHead(response_code), response_string));
+      network::CreateURLResponseHead(response_code), response_string));
   // Give a chance for GCMStoreImpl::Backend to finish persisting data.
   PumpLoopUntilIdle();
 }
@@ -570,7 +570,7 @@
 
   EXPECT_TRUE(url_loader_factory()->SimulateResponseForPendingRequest(
       GURL(kRegisterUrl), network::URLLoaderCompletionStatus(net::OK),
-      network::CreateResourceResponseHead(net::HTTP_OK), response));
+      network::CreateURLResponseHead(net::HTTP_OK), response));
 
   // Give a chance for GCMStoreImpl::Backend to finish persisting data.
   PumpLoopUntilIdle();
@@ -583,7 +583,7 @@
 
   EXPECT_TRUE(url_loader_factory()->SimulateResponseForPendingRequest(
       GURL(kRegisterUrl), network::URLLoaderCompletionStatus(net::OK),
-      network::CreateResourceResponseHead(net::HTTP_OK), response));
+      network::CreateURLResponseHead(net::HTTP_OK), response));
 
   // Give a chance for GCMStoreImpl::Backend to finish persisting data.
   PumpLoopUntilIdle();
@@ -1692,7 +1692,7 @@
 
   EXPECT_TRUE(url_loader_factory()->SimulateResponseForPendingRequest(
       GURL(kRegisterUrl), network::URLLoaderCompletionStatus(net::OK),
-      network::CreateResourceResponseHead(net::HTTP_OK), response));
+      network::CreateURLResponseHead(net::HTTP_OK), response));
 
   // Give a chance for GCMStoreImpl::Backend to finish persisting data.
   PumpLoopUntilIdle();
diff --git a/components/gcm_driver/gcm_driver_unittest.cc b/components/gcm_driver/gcm_driver_unittest.cc
index 2d95a6f..39a43ba 100644
--- a/components/gcm_driver/gcm_driver_unittest.cc
+++ b/components/gcm_driver/gcm_driver_unittest.cc
@@ -211,14 +211,14 @@
     const network::DataElement& body = body_elements->back();
     send_web_push_message_payload_ = std::string(body.bytes(), body.length());
 
-    network::ResourceResponseHead response_head =
-        network::CreateResourceResponseHead(*completion_status);
-    response_head.headers->AddHeader(
+    auto response_head = network::CreateURLResponseHead(*completion_status);
+    response_head->headers->AddHeader(
         "location:https://fcm.googleapis.com/message_id");
 
     test_url_loader_factory_.SimulateResponseForPendingRequest(
         pendingRequest->request.url,
-        network::URLLoaderCompletionStatus(net::OK), response_head, "");
+        network::URLLoaderCompletionStatus(net::OK), std::move(response_head),
+        "");
   }
 
   if (wait_to_finish == WAIT)
diff --git a/components/gcm_driver/web_push_sender_unittest.cc b/components/gcm_driver/web_push_sender_unittest.cc
index 8fcd0691..8c55428 100644
--- a/components/gcm_driver/web_push_sender_unittest.cc
+++ b/components/gcm_driver/web_push_sender_unittest.cc
@@ -114,14 +114,13 @@
   const network::DataElement& body = body_elements->back();
   ASSERT_EQ("payload", std::string(body.bytes(), body.length()));
 
-  network::ResourceResponseHead response_head =
-      network::CreateResourceResponseHead(net::HTTP_OK);
-  response_head.headers->AddHeader(
+  auto response_head = network::CreateURLResponseHead(net::HTTP_OK);
+  response_head->headers->AddHeader(
       "location:https://fcm.googleapis.com/message_id");
 
   loader().SimulateResponseForPendingRequest(
       pendingRequest->request.url, network::URLLoaderCompletionStatus(net::OK),
-      response_head, "");
+      std::move(response_head), "");
 
   ASSERT_EQ(SendWebPushMessageResult::kSuccessful, result);
   ASSERT_EQ("message_id", message_id);
@@ -211,7 +210,7 @@
   loader().SimulateResponseForPendingRequest(
       loader().GetPendingRequest(0)->request.url,
       network::URLLoaderCompletionStatus(GetParam().error_code),
-      network::CreateResourceResponseHead(GetParam().http_status), "");
+      network::CreateURLResponseHead(GetParam().http_status), "");
 
   ASSERT_EQ(GetParam().expected_result, result);
   ASSERT_FALSE(message_id);
diff --git a/components/image_fetcher/DEPS b/components/image_fetcher/DEPS
index c8c46e1..daecc95 100644
--- a/components/image_fetcher/DEPS
+++ b/components/image_fetcher/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+net",
   "+services/network/public/cpp",
+  "+services/network/public/mojom",
   "+services/network/test",
   "+ui/gfx/geometry",
   "+ui/gfx/image",
diff --git a/components/image_fetcher/core/image_data_fetcher_unittest.cc b/components/image_fetcher/core/image_data_fetcher_unittest.cc
index 5a6e56b..f9f215ad 100644
--- a/components/image_fetcher/core/image_data_fetcher_unittest.cc
+++ b/components/image_fetcher/core/image_data_fetcher_unittest.cc
@@ -85,16 +85,17 @@
   EXPECT_EQ(pending_request->credentials_mode,
             network::mojom::CredentialsMode::kOmit);
 
-  network::ResourceResponseHead head;
+  auto head = network::mojom::URLResponseHead::New();
   std::string raw_header =
       "HTTP/1.1 200 OK\n"
       "Content-type: image/png\n\n";
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
       net::HttpUtil::AssembleRawHeaders(raw_header));
-  head.mime_type = "image/png";
+  head->mime_type = "image/png";
   network::URLLoaderCompletionStatus status;
   status.decoded_body_length = content.size();
-  test_url_loader_factory_.AddResponse(GURL(kImageURL), head, content, status);
+  test_url_loader_factory_.AddResponse(GURL(kImageURL), std::move(head),
+                                       content, status);
   base::RunLoop().RunUntilIdle();
 }
 
@@ -119,16 +120,17 @@
   EXPECT_EQ(pending_request->credentials_mode,
             network::mojom::CredentialsMode::kInclude);
 
-  network::ResourceResponseHead head;
+  auto head = network::mojom::URLResponseHead::New();
   std::string raw_header =
       "HTTP/1.1 200 OK\n"
       "Content-type: image/png\n\n";
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
       net::HttpUtil::AssembleRawHeaders(raw_header));
-  head.mime_type = "image/png";
+  head->mime_type = "image/png";
   network::URLLoaderCompletionStatus status;
   status.decoded_body_length = content.size();
-  test_url_loader_factory_.AddResponse(GURL(kImageURL), head, content, status);
+  test_url_loader_factory_.AddResponse(GURL(kImageURL), std::move(head),
+                                       content, status);
   base::RunLoop().RunUntilIdle();
 }
 
@@ -150,16 +152,17 @@
   // Check to make sure the request is pending, and provide a response.
   EXPECT_TRUE(test_url_loader_factory_.IsPending(kImageURL));
 
-  network::ResourceResponseHead head;
+  auto head = network::mojom::URLResponseHead::New();
   std::string raw_header =
       "HTTP/1.1 404 Not Found\n"
       "Content-type: image/png\n\n";
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
       net::HttpUtil::AssembleRawHeaders(raw_header));
-  head.mime_type = "image/png";
+  head->mime_type = "image/png";
   network::URLLoaderCompletionStatus status;
   status.decoded_body_length = content.size();
-  test_url_loader_factory_.AddResponse(GURL(kImageURL), head, content, status);
+  test_url_loader_factory_.AddResponse(GURL(kImageURL), std::move(head),
+                                       content, status);
   base::RunLoop().RunUntilIdle();
 }
 
@@ -182,17 +185,18 @@
   // Check to make sure the request is pending, and provide a response.
   EXPECT_TRUE(test_url_loader_factory_.IsPending(kImageURL));
 
-  network::ResourceResponseHead head;
+  auto head = network::mojom::URLResponseHead::New();
   std::string raw_header =
       "HTTP/1.1 404 Not Found\n"
       "Content-type: image/png\n"
       "Content-location: http://test-location/image.png\n\n";
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
       net::HttpUtil::AssembleRawHeaders(raw_header));
-  head.mime_type = "image/png";
+  head->mime_type = "image/png";
   network::URLLoaderCompletionStatus status;
   status.decoded_body_length = content.size();
-  test_url_loader_factory_.AddResponse(GURL(kImageURL), head, content, status);
+  test_url_loader_factory_.AddResponse(GURL(kImageURL), std::move(head),
+                                       content, status);
   base::RunLoop().RunUntilIdle();
 }
 
@@ -211,11 +215,12 @@
   // Check to make sure the request is pending, and provide a response.
   EXPECT_TRUE(test_url_loader_factory_.IsPending(kImageURL));
 
-  network::ResourceResponseHead head;
-  head.mime_type = "image/png";
+  auto head = network::mojom::URLResponseHead::New();
+  head->mime_type = "image/png";
   network::URLLoaderCompletionStatus status;
   status.error_code = net::ERR_INVALID_URL;
-  test_url_loader_factory_.AddResponse(GURL(kImageURL), head, "", status);
+  test_url_loader_factory_.AddResponse(GURL(kImageURL), std::move(head), "",
+                                       status);
   base::RunLoop().RunUntilIdle();
 }
 
diff --git a/components/image_fetcher/ios/ios_image_data_fetcher_wrapper_unittest.mm b/components/image_fetcher/ios/ios_image_data_fetcher_wrapper_unittest.mm
index 77876242..88d4a7d5 100644
--- a/components/image_fetcher/ios/ios_image_data_fetcher_wrapper_unittest.mm
+++ b/components/image_fetcher/ios/ios_image_data_fetcher_wrapper_unittest.mm
@@ -19,6 +19,7 @@
 #include "net/http/http_response_headers.h"
 #include "net/http/http_status_code.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/platform_test.h"
@@ -172,13 +173,14 @@
 
   std::string content(reinterpret_cast<const char*>(kWEBPImage),
                       sizeof(kWEBPImage));
-  network::ResourceResponseHead head;
-  head.headers = new net::HttpResponseHeaders(
+  network::mojom::URLResponseHeadPtr head =
+      network::mojom::URLResponseHead::New();
+  head->headers = new net::HttpResponseHeaders(
       std::string(kWEBPHeaderResponse, base::size(kWEBPHeaderResponse)));
-  head.mime_type = "image/webp";
+  head->mime_type = "image/webp";
   network::URLLoaderCompletionStatus status;
   status.decoded_body_length = content.size();
-  factory_.AddResponse(GURL(kTestUrl), head, content, status);
+  factory_.AddResponse(GURL(kTestUrl), std::move(head), content, status);
   environment_.RunUntilIdle();
   EXPECT_NE(nil, result_);
   EXPECT_TRUE(called_);
@@ -198,13 +200,14 @@
   SetupFetcher();
 
   std::string content = "This is not a valid WebP image";
-  network::ResourceResponseHead head;
-  head.headers = new net::HttpResponseHeaders(
+  network::mojom::URLResponseHeadPtr head =
+      network::mojom::URLResponseHead::New();
+  head->headers = new net::HttpResponseHeaders(
       std::string(kWEBPHeaderResponse, base::size(kWEBPHeaderResponse)));
-  head.mime_type = "image/webp";
+  head->mime_type = "image/webp";
   network::URLLoaderCompletionStatus status;
   status.decoded_body_length = content.size();
-  factory_.AddResponse(GURL(kTestUrl), head, content, status);
+  factory_.AddResponse(GURL(kTestUrl), std::move(head), content, status);
   environment_.RunUntilIdle();
   EXPECT_EQ(nil, result_);
   EXPECT_TRUE(called_);
diff --git a/components/invalidation/impl/per_user_topic_registration_manager_unittest.cc b/components/invalidation/impl/per_user_topic_registration_manager_unittest.cc
index 03dde31..9ac35ec 100644
--- a/components/invalidation/impl/per_user_topic_registration_manager_unittest.cc
+++ b/components/invalidation/impl/per_user_topic_registration_manager_unittest.cc
@@ -69,11 +69,11 @@
   return topic_set;
 }
 
-network::ResourceResponseHead CreateHeadersForTest(int responce_code) {
-  network::ResourceResponseHead head;
-  head.headers = new net::HttpResponseHeaders(base::StringPrintf(
+network::mojom::URLResponseHeadPtr CreateHeadersForTest(int responce_code) {
+  auto head = network::mojom::URLResponseHead::New();
+  head->headers = new net::HttpResponseHeaders(base::StringPrintf(
       "HTTP/1.1 %d OK\nContent-type: text/html\n\n", responce_code));
-  head.mime_type = "text/html";
+  head->mime_type = "text/html";
   return head;
 }
 
diff --git a/components/invalidation/impl/per_user_topic_registration_request_unittest.cc b/components/invalidation/impl/per_user_topic_registration_request_unittest.cc
index 17d7815..9982d09 100644
--- a/components/invalidation/impl/per_user_topic_registration_request_unittest.cc
+++ b/components/invalidation/impl/per_user_topic_registration_request_unittest.cc
@@ -51,11 +51,11 @@
   return *expected == *actual;
 }
 
-network::ResourceResponseHead CreateHeadersForTest(int responce_code) {
-  network::ResourceResponseHead head;
-  head.headers = new net::HttpResponseHeaders(base::StringPrintf(
+network::mojom::URLResponseHeadPtr CreateHeadersForTest(int responce_code) {
+  auto head = network::mojom::URLResponseHead::New();
+  head->headers = new net::HttpResponseHeaders(base::StringPrintf(
       "HTTP/1.1 %d OK\nContent-type: text/html\n\n", responce_code));
-  head.mime_type = "text/html";
+  head->mime_type = "text/html";
   return head;
 }
 
diff --git a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
index 6c28c7d..a2193d5 100644
--- a/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
+++ b/components/ntp_snippets/remote/remote_suggestions_fetcher_impl_unittest.cc
@@ -239,17 +239,17 @@
                        const std::string& response_data,
                        net::HttpStatusCode response_code,
                        net::Error error) {
-    network::ResourceResponseHead head;
+    auto head = network::mojom::URLResponseHead::New();
     std::string headers(base::StringPrintf(
         "HTTP/1.1 %d %s\nContent-type: application/json\n\n",
         static_cast<int>(response_code), GetHttpReasonPhrase(response_code)));
-    head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+    head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
         net::HttpUtil::AssembleRawHeaders(headers));
-    head.mime_type = "application/json";
+    head->mime_type = "application/json";
     network::URLLoaderCompletionStatus status(error);
     status.decoded_body_length = response_data.size();
-    test_url_loader_factory_.AddResponse(request_url, head, response_data,
-                                         status);
+    test_url_loader_factory_.AddResponse(request_url, std::move(head),
+                                         response_data, status);
   }
 
  protected:
diff --git a/components/offline_pages/core/prefetch/prefetch_request_test_base.cc b/components/offline_pages/core/prefetch/prefetch_request_test_base.cc
index 66ac5618..d784d18 100644
--- a/components/offline_pages/core/prefetch/prefetch_request_test_base.cc
+++ b/components/offline_pages/core/prefetch/prefetch_request_test_base.cc
@@ -51,17 +51,17 @@
   network::URLLoaderCompletionStatus completion_status(net_error);
   test_url_loader_factory_.SimulateResponseForPendingRequest(
       GetPendingRequest(0)->request.url, completion_status,
-      network::ResourceResponseHead(), std::string());
+      network::mojom::URLResponseHead::New(), std::string());
 }
 
 void PrefetchRequestTestBase::RespondWithHttpError(
     net::HttpStatusCode http_error) {
   int pending_requests_count = test_url_loader_factory_.NumPending();
-  auto resource_response_head = network::CreateResourceResponseHead(http_error);
+  auto url_response_head = network::CreateURLResponseHead(http_error);
   DCHECK(pending_requests_count > 0);
   test_url_loader_factory_.SimulateResponseForPendingRequest(
       GetPendingRequest(0)->request.url,
-      network::URLLoaderCompletionStatus(net::OK), resource_response_head,
+      network::URLLoaderCompletionStatus(net::OK), std::move(url_response_head),
       std::string());
 }
 
@@ -75,11 +75,11 @@
     net::HttpStatusCode http_error,
     const std::string& data) {
   int pending_requests_count = test_url_loader_factory_.NumPending();
-  auto resource_response_head = network::CreateResourceResponseHead(http_error);
+  auto url_response_head = network::CreateURLResponseHead(http_error);
   DCHECK(pending_requests_count > 0);
   test_url_loader_factory_.SimulateResponseForPendingRequest(
       GetPendingRequest(0)->request.url,
-      network::URLLoaderCompletionStatus(net::OK), resource_response_head,
+      network::URLLoaderCompletionStatus(net::OK), std::move(url_response_head),
       data);
 }
 
diff --git a/components/omnibox/browser/location_bar_model_impl.cc b/components/omnibox/browser/location_bar_model_impl.cc
index 8da79e2..3ea39cb8 100644
--- a/components/omnibox/browser/location_bar_model_impl.cc
+++ b/components/omnibox/browser/location_bar_model_impl.cc
@@ -187,7 +187,7 @@
 
   switch (GetSecurityLevel()) {
     case security_state::NONE:
-    case security_state::HTTP_SHOW_WARNING:
+    case security_state::WARNING:
       return omnibox::kHttpIcon;
     case security_state::EV_SECURE:
     case security_state::SECURE:
@@ -218,7 +218,7 @@
     return SecureChipText(l10n_util::GetStringUTF16(IDS_OFFLINE_VERBOSE_STATE));
 
   switch (GetSecurityLevel()) {
-    case security_state::HTTP_SHOW_WARNING:
+    case security_state::WARNING:
       return SecureChipText(
           l10n_util::GetStringUTF16(IDS_NOT_SECURE_VERBOSE_STATE));
     case security_state::EV_SECURE: {
diff --git a/components/omnibox/browser/omnibox_edit_model.cc b/components/omnibox/browser/omnibox_edit_model.cc
index c55d2a71..b649e89 100644
--- a/components/omnibox/browser/omnibox_edit_model.cc
+++ b/components/omnibox/browser/omnibox_edit_model.cc
@@ -1636,20 +1636,9 @@
 }
 
 size_t OmniboxEditModel::GetNewSelectedLine(int count) {
-  if (!OmniboxFieldTrial::IsOmniboxWrapPopupPositionEnabled()) {
-    if (count < 0) {
-      if ((size_t)-count >= popup_model()->selected_line())
-        return 0;
-    } else if (count + popup_model()->selected_line() >=
-               popup_model()->result().size()) {
-      return popup_model()->result().size() - 1;
-    }
-    return popup_model()->selected_line() + count;
-  } else {
-    int line_no = (static_cast<int>(popup_model()->selected_line()) + count) %
-                  static_cast<int>(popup_model()->result().size());
-    if (line_no < 0)
-      line_no += popup_model()->result().size();
-    return line_no;
-  }
+  int line_no = (static_cast<int>(popup_model()->selected_line()) + count) %
+                static_cast<int>(popup_model()->result().size());
+  if (line_no < 0)
+    line_no += popup_model()->result().size();
+  return line_no;
 }
diff --git a/components/omnibox/browser/omnibox_field_trial.cc b/components/omnibox/browser/omnibox_field_trial.cc
index c324294..108e4b9 100644
--- a/components/omnibox/browser/omnibox_field_trial.cc
+++ b/components/omnibox/browser/omnibox_field_trial.cc
@@ -685,10 +685,6 @@
   return base::FeatureList::IsEnabled(omnibox::kOmniboxMaxURLMatches);
 }
 
-bool OmniboxFieldTrial::IsOmniboxWrapPopupPositionEnabled() {
-  return base::FeatureList::IsEnabled(omnibox::kOmniboxWrapPopupPosition);
-}
-
 bool OmniboxFieldTrial::IsOnDeviceHeadProviderEnabledForIncognito() {
   return base::GetFieldTrialParamByFeatureAsBool(omnibox::kOnDeviceHeadProvider,
                                                  "EnableForIncongnito", false);
diff --git a/components/omnibox/browser/omnibox_field_trial.h b/components/omnibox/browser/omnibox_field_trial.h
index 0d68d3b..366b965 100644
--- a/components/omnibox/browser/omnibox_field_trial.h
+++ b/components/omnibox/browser/omnibox_field_trial.h
@@ -417,10 +417,6 @@
 // is enabled.
 bool IsMaxURLMatchesFeatureEnabled();
 
-// Returns whether the feature to allow the Omnibox pop-up position to wrap
-// between top and bottom is enabled.
-bool IsOmniboxWrapPopupPositionEnabled();
-
 // Returns whether on device head provider is enabled for incognito mode.
 bool IsOnDeviceHeadProviderEnabledForIncognito();
 
diff --git a/components/omnibox/browser/omnibox_popup_model_unittest.cc b/components/omnibox/browser/omnibox_popup_model_unittest.cc
index d69e44e..5c1ea279 100644
--- a/components/omnibox/browser/omnibox_popup_model_unittest.cc
+++ b/components/omnibox/browser/omnibox_popup_model_unittest.cc
@@ -96,9 +96,6 @@
 }
 
 TEST_F(OmniboxPopupModelTest, PopupPositionChanging) {
-  base::test::ScopedFeatureList feature_list;
-  feature_list.InitAndDisableFeature(omnibox::kOmniboxWrapPopupPosition);
-
   ACMatches matches;
   for (size_t i = 0; i < 3; ++i) {
     AutocompleteMatch match(nullptr, 1000, false,
@@ -115,28 +112,16 @@
   result->SortAndCull(input, nullptr);
   popup_model()->OnResultChanged();
   EXPECT_EQ(0u, model()->popup_model()->selected_line());
-  model()->OnUpOrDownKeyPressed(1);
-  EXPECT_EQ(1u, model()->popup_model()->selected_line());
-  model()->OnUpOrDownKeyPressed(-1);
-  EXPECT_EQ(0u, model()->popup_model()->selected_line());
-  model()->OnUpOrDownKeyPressed(2);
-  EXPECT_EQ(2u, model()->popup_model()->selected_line());
-  // Cap at number of results.
-  model()->OnUpOrDownKeyPressed(2);
-  EXPECT_EQ(2u, model()->popup_model()->selected_line());
-  // Cap at 0 too.
-  model()->OnUpOrDownKeyPressed(-3);
-  EXPECT_EQ(0u, model()->popup_model()->selected_line());
-
-  feature_list.Reset();
-  feature_list.InitAndEnableFeature(omnibox::kOmniboxWrapPopupPosition);
-  // Test wrapping.
-  model()->OnUpOrDownKeyPressed(-1);
-  EXPECT_EQ(2u, model()->popup_model()->selected_line());
-  model()->OnUpOrDownKeyPressed(1);
-  EXPECT_EQ(0u, model()->popup_model()->selected_line());
-  model()->OnUpOrDownKeyPressed(1);
-  EXPECT_EQ(1u, model()->popup_model()->selected_line());
+  // Test moving and wrapping down.
+  for (size_t n : {1, 2, 0}) {
+    model()->OnUpOrDownKeyPressed(1);
+    EXPECT_EQ(n, model()->popup_model()->selected_line());
+  }
+  // And down.
+  for (size_t n : {2, 1, 0}) {
+    model()->OnUpOrDownKeyPressed(-1);
+    EXPECT_EQ(n, model()->popup_model()->selected_line());
+  }
 }
 
 TEST_F(OmniboxPopupModelTest, ComputeMatchMaxWidths) {
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc
index 1c03a13..2ec98aa6 100644
--- a/components/omnibox/common/omnibox_features.cc
+++ b/components/omnibox/common/omnibox_features.cc
@@ -122,11 +122,6 @@
     "OmniboxTabSwitchSuggestionsDedicatedRow",
     base::FEATURE_DISABLED_BY_DEFAULT};
 
-// Feature that enables wrapping the Omnibox position between top and bottom.
-// The feature is enabled by default, but remains as a kill-switch.
-const base::Feature kOmniboxWrapPopupPosition{"OmniboxWrapPopupPosition",
-                                              base::FEATURE_ENABLED_BY_DEFAULT};
-
 // Feature used to reverse the sense of the tab switch button. Selecting the
 // suggestion will switch to the tab, while the button will navigate
 // locally.
diff --git a/components/omnibox/common/omnibox_features.h b/components/omnibox/common/omnibox_features.h
index 028d931c..70e5d1b 100644
--- a/components/omnibox/common/omnibox_features.h
+++ b/components/omnibox/common/omnibox_features.h
@@ -25,7 +25,6 @@
 extern const base::Feature kOmniboxTailSuggestions;
 extern const base::Feature kOmniboxTabSwitchSuggestions;
 extern const base::Feature kOmniboxTabSwitchSuggestionsDedicatedRow;
-extern const base::Feature kOmniboxWrapPopupPosition;
 extern const base::Feature kOmniboxReverseTabSwitchLogic;
 extern const base::Feature kExperimentalKeywordMode;
 extern const base::Feature kOmniboxPedalSuggestions;
diff --git a/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc b/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc
index b86f51f..9570179 100644
--- a/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc
+++ b/components/password_manager/core/browser/android_affiliation/affiliation_fetcher_unittest.cc
@@ -105,11 +105,11 @@
   }
 
   void SetupNetworkErrorResponse() {
-    network::ResourceResponseHead head =
-        network::CreateResourceResponseHead(net::HTTP_INTERNAL_SERVER_ERROR);
-    head.mime_type = "application/protobuf";
+    auto head = network::CreateURLResponseHead(net::HTTP_INTERNAL_SERVER_ERROR);
+    head->mime_type = "application/protobuf";
     network::URLLoaderCompletionStatus status(net::ERR_NETWORK_CHANGED);
-    test_url_loader_factory_.AddResponse(interception_url(), head, "", status);
+    test_url_loader_factory_.AddResponse(interception_url(), std::move(head),
+                                         "", status);
   }
 
   void WaitForResponse() { task_environment_.RunUntilIdle(); }
diff --git a/components/policy/core/common/cloud/external_policy_data_fetcher_unittest.cc b/components/policy/core/common/cloud/external_policy_data_fetcher_unittest.cc
index e839482..d380453 100644
--- a/components/policy/core/common/cloud/external_policy_data_fetcher_unittest.cc
+++ b/components/policy/core/common/cloud/external_policy_data_fetcher_unittest.cc
@@ -171,7 +171,7 @@
 
   // Make the fetch fail due to an interrupted connection.
   test_url_loader_factory_.AddResponse(
-      GURL(kExternalPolicyDataURLs[0]), network::ResourceResponseHead(),
+      GURL(kExternalPolicyDataURLs[0]), network::mojom::URLResponseHead::New(),
       std::string(),
       network::URLLoaderCompletionStatus(net::ERR_CONNECTION_RESET));
 
@@ -196,7 +196,7 @@
 
   // Make the fetch fail due to a network error.
   test_url_loader_factory_.AddResponse(
-      GURL(kExternalPolicyDataURLs[0]), network::ResourceResponseHead(),
+      GURL(kExternalPolicyDataURLs[0]), network::mojom::URLResponseHead::New(),
       std::string(),
       network::URLLoaderCompletionStatus(net::ERR_NETWORK_CHANGED));
 
diff --git a/components/policy/core/common/cloud/external_policy_data_updater_unittest.cc b/components/policy/core/common/cloud/external_policy_data_updater_unittest.cc
index ff036ea7..56ad4d54 100644
--- a/components/policy/core/common/cloud/external_policy_data_updater_unittest.cc
+++ b/components/policy/core/common/cloud/external_policy_data_updater_unittest.cc
@@ -191,7 +191,7 @@
 
   // Make the first fetch fail due to an interrupted connection.
   test_url_loader_factory_.AddResponse(
-      GURL(kExternalPolicyDataURLs[0]), network::ResourceResponseHead(),
+      GURL(kExternalPolicyDataURLs[0]), network::mojom::URLResponseHead::New(),
       std::string(),
       network::URLLoaderCompletionStatus(net::ERR_NETWORK_CHANGED));
   base::RunLoop().RunUntilIdle();
@@ -220,7 +220,7 @@
 
   // Make the first fetch fail with a server error.
   test_url_loader_factory_.AddResponse(
-      GURL(kExternalPolicyDataURLs[0]), network::ResourceResponseHead(),
+      GURL(kExternalPolicyDataURLs[0]), network::mojom::URLResponseHead::New(),
       std::string(),
       network::URLLoaderCompletionStatus(net::HTTP_INTERNAL_SERVER_ERROR));
   base::RunLoop().RunUntilIdle();
diff --git a/components/policy/resources/policy_templates.json b/components/policy/resources/policy_templates.json
index 0244913..08b7f94 100644
--- a/components/policy/resources/policy_templates.json
+++ b/components/policy/resources/policy_templates.json
@@ -17993,6 +17993,32 @@
 
       See https://www.chromestatus.com/feature/4664843055398912 .''',
     },
+    {
+      'name': 'TotalMemoryLimitMb',
+      'owners': ['catan-team@chromium.org'],
+      'type': 'int',
+      'schema': {
+        'type': 'integer',
+        'minimum': 2048,
+      },
+      'supported_on': ['chrome.win:79-', 'chrome.mac:79-'],
+      'future': True,
+      'features': {
+        'dynamic_refresh': True,
+        'per_profile': False,
+      },
+      'example_value': 2048,
+      'id': 616,
+      'caption': '''Set limit on megabytes of memory a single Chrome instance can use.''',
+      'tags': [],
+      'desc': '''Configures the amount of memory that a single <ph name="PRODUCT_NAME">$1<ex>Google Chrome</ex></ph> instance can use before tabs start being discarded (I.E. the memory used by the tab will be freed and the tab will have to be reloaded when switched to) to save memory.
+
+      If the policy is set, browser will begin to discard tabs to save memory once the limitation is exceeded. However, there is no guarantee that the browser is always running under the limit. Any value under 2048 will be rounded up to 2048.
+
+      If this policy is not set, the browser will only begin attempts to save memory once it has detected that the amount of physical memory on its machine is low.''',
+
+      'label': '''Set memory limit for Chrome instances''',
+    }
   ],
 
   'messages': {
@@ -18801,6 +18827,6 @@
   ],
   'placeholders': [],
   'deleted_policy_ids': [412, 546, 562, 569],
-  'highest_id_currently_used': 615,
+  'highest_id_currently_used': 616,
   'highest_atomic_group_id_currently_used': 37
 }
diff --git a/components/rappor/log_uploader_unittest.cc b/components/rappor/log_uploader_unittest.cc
index e4f08d6e..b63e7bdb 100644
--- a/components/rappor/log_uploader_unittest.cc
+++ b/components/rappor/log_uploader_unittest.cc
@@ -90,12 +90,13 @@
 TEST_F(LogUploaderTest, Rejection) {
   TestLogUploader uploader(test_url_loader_factory_.GetSafeWeakWrapper());
 
-  network::ResourceResponseHead response_head;
+  auto response_head = network::mojom::URLResponseHead::New();
   std::string headers("HTTP/1.1 400 Bad Request\nContent-type: text/html\n\n");
-  response_head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+  response_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
       net::HttpUtil::AssembleRawHeaders(headers));
-  response_head.mime_type = "text/html";
-  test_url_loader_factory_.AddResponse(GURL(kTestServerURL), response_head, "",
+  response_head->mime_type = "text/html";
+  test_url_loader_factory_.AddResponse(GURL(kTestServerURL),
+                                       std::move(response_head), "",
                                        network::URLLoaderCompletionStatus());
 
   uploader.QueueLog("log1");
@@ -107,13 +108,14 @@
 TEST_F(LogUploaderTest, Failure) {
   TestLogUploader uploader(test_url_loader_factory_.GetSafeWeakWrapper());
 
-  network::ResourceResponseHead response_head;
+  auto response_head = network::mojom::URLResponseHead::New();
   std::string headers(
       "HTTP/1.1 500 Internal Server Error\nContent-type: text/html\n\n");
-  response_head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+  response_head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
       net::HttpUtil::AssembleRawHeaders(headers));
-  response_head.mime_type = "text/html";
-  test_url_loader_factory_.AddResponse(GURL(kTestServerURL), response_head, "",
+  response_head->mime_type = "text/html";
+  test_url_loader_factory_.AddResponse(GURL(kTestServerURL),
+                                       std::move(response_head), "",
                                        network::URLLoaderCompletionStatus());
 
   uploader.QueueLog("log1");
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 f889410..d915e03 100644
--- a/components/safe_browsing/password_protection/password_protection_service_unittest.cc
+++ b/components/safe_browsing/password_protection/password_protection_service_unittest.cc
@@ -805,9 +805,9 @@
 TEST_P(PasswordProtectionServiceTest, TestResponseFetchFailed) {
   histograms_.ExpectTotalCount(kPasswordOnFocusRequestOutcomeHistogram, 0);
   // Set up failed response.
-  network::ResourceResponseHead head;
   network::URLLoaderCompletionStatus status(net::ERR_FAILED);
-  test_url_loader_factory_.AddResponse(url_, head, std::string(), status);
+  test_url_loader_factory_.AddResponse(
+      url_, network::mojom::URLResponseHead::New(), std::string(), status);
   std::unique_ptr<content::WebContents> web_contents = GetWebContents();
 
   InitializeAndStartPasswordOnFocusRequest(false /* match whitelist */,
diff --git a/components/safe_search_api/safe_search/safe_search_url_checker_client_unittest.cc b/components/safe_search_api/safe_search/safe_search_url_checker_client_unittest.cc
index 4261315e..729650f 100644
--- a/components/safe_search_api/safe_search/safe_search_url_checker_client_unittest.cc
+++ b/components/safe_search_api/safe_search/safe_search_url_checker_client_unittest.cc
@@ -86,7 +86,7 @@
     network::URLLoaderCompletionStatus status(error);
     status.decoded_body_length = response.size();
     test_url_loader_factory_.AddResponse(GURL(kSafeSearchApiUrl),
-                                         network::ResourceResponseHead(),
+                                         network::mojom::URLResponseHead::New(),
                                          response, status);
   }
 
diff --git a/components/safe_search_api/stub_url_checker.cc b/components/safe_search_api/stub_url_checker.cc
index eeaa36b..b32462d 100644
--- a/components/safe_search_api/stub_url_checker.cc
+++ b/components/safe_search_api/stub_url_checker.cc
@@ -69,7 +69,7 @@
   network::URLLoaderCompletionStatus status(error);
   status.decoded_body_length = response.size();
   test_url_loader_factory_.AddResponse(GURL(kSafeSearchApiUrl),
-                                       network::ResourceResponseHead(),
+                                       network::mojom::URLResponseHead::New(),
                                        response, status);
 }
 
diff --git a/components/search_provider_logos/logo_service_impl_unittest.cc b/components/search_provider_logos/logo_service_impl_unittest.cc
index b0ea8b2..54608b2 100644
--- a/components/search_provider_logos/logo_service_impl_unittest.cc
+++ b/components/search_provider_logos/logo_service_impl_unittest.cc
@@ -461,18 +461,18 @@
   GURL url_with_fp = AppendFingerprintParamToDoodleURL(
       AppendPreliminaryParamsToDoodleURL(false, DoodleURL()), fingerprint);
 
-  network::ResourceResponseHead head;
+  auto head = network::mojom::URLResponseHead::New();
   std::string headers(base::StringPrintf(
       "HTTP/1.1 %d %s\nContent-type: text/html\n\n",
       static_cast<int>(response_code), GetHttpReasonPhrase(response_code)));
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
       net::HttpUtil::AssembleRawHeaders(headers));
-  head.mime_type = "text/html";
+  head->mime_type = "text/html";
   network::URLLoaderCompletionStatus status;
   status.error_code = error_code;
   status.decoded_body_length = response_when_fingerprint.size();
 
-  test_url_loader_factory_.AddResponse(url_with_fp, head,
+  test_url_loader_factory_.AddResponse(url_with_fp, std::move(head),
                                        response_when_fingerprint, status);
 }
 
diff --git a/components/security_state/content/content_utils.cc b/components/security_state/content/content_utils.cc
index 8c55c0d..1576ef3 100644
--- a/components/security_state/content/content_utils.cc
+++ b/components/security_state/content/content_utils.cc
@@ -41,7 +41,7 @@
     security_state::SecurityLevel security_level) {
   switch (security_level) {
     case security_state::NONE:
-    case security_state::HTTP_SHOW_WARNING:
+    case security_state::WARNING:
       return blink::kWebSecurityStyleNeutral;
     case security_state::SECURE_WITH_POLICY_INSTALLED_CERT:
     case security_state::EV_SECURE:
diff --git a/components/security_state/content/content_utils_unittest.cc b/components/security_state/content/content_utils_unittest.cc
index 7935219..af6ec8b 100644
--- a/components/security_state/content/content_utils_unittest.cc
+++ b/components/security_state/content/content_utils_unittest.cc
@@ -584,14 +584,14 @@
   }
 }
 
-// Tests that a security level of HTTP_SHOW_WARNING produces
+// Tests that a security level of WARNING produces
 // blink::WebSecurityStyleNeutral.
 TEST(SecurityStateContentUtilsTest, HTTPWarning) {
   security_state::VisibleSecurityState visible_security_state;
   visible_security_state.url = GURL("http://scheme-is-not-cryptographic.test");
   content::SecurityStyleExplanations explanations;
   blink::WebSecurityStyle security_style = GetSecurityStyle(
-      security_state::HTTP_SHOW_WARNING, visible_security_state, &explanations);
+      security_state::WARNING, visible_security_state, &explanations);
   EXPECT_EQ(blink::kWebSecurityStyleNeutral, security_style);
   // Verify no explanation was shown.
   EXPECT_EQ(0u, explanations.neutral_explanations.size());
diff --git a/components/security_state/core/security_state.cc b/components/security_state/core/security_state.cc
index 3ee6b82..f0b244c 100644
--- a/components/security_state/core/security_state.cc
+++ b/components/security_state/core/security_state.cc
@@ -48,7 +48,7 @@
 
   // Default to dangerous on editing form fields and otherwise
   // warning.
-  return input_events.insecure_field_edited ? DANGEROUS : HTTP_SHOW_WARNING;
+  return input_events.insecure_field_edited ? DANGEROUS : WARNING;
 }
 
 std::string GetHistogramSuffixForSecurityLevel(
@@ -60,8 +60,8 @@
       return "SECURE";
     case NONE:
       return "NONE";
-    case HTTP_SHOW_WARNING:
-      return "HTTP_SHOW_WARNING";
+    case WARNING:
+      return "WARNING";
     case SECURE_WITH_POLICY_INSTALLED_CERT:
       return "SECURE_WITH_POLICY_INSTALLED_CERT";
     case DANGEROUS:
@@ -118,7 +118,7 @@
   //
   // Display a "Not secure" badge for all these URLs.
   if (url.SchemeIs(url::kDataScheme) || url.SchemeIs(url::kFtpScheme)) {
-    return HTTP_SHOW_WARNING;
+    return WARNING;
   }
 
   // Display DevTools pages as neutral since we can't be confident the page
diff --git a/components/security_state/core/security_state.h b/components/security_state/core/security_state.h
index b624933..ca1209c 100644
--- a/components/security_state/core/security_state.h
+++ b/components/security_state/core/security_state.h
@@ -40,7 +40,8 @@
 // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.security_state
 // GENERATED_JAVA_CLASS_NAME_OVERRIDE: ConnectionSecurityLevel
 enum SecurityLevel {
-  // HTTP/no URL/HTTPS but with insecure passive content on the page.
+  // Neutral; neither positively secure nor insecure. Used for e.g. some types
+  // of non-http/https URLs.
   NONE = 0,
 
   // HTTP, in a case where we want to show a visible warning about the page's
@@ -49,7 +50,8 @@
   // The criteria used to classify pages as NONE vs. HTTP_SHOW_WARNING will
   // change over time. Eventually, NONE will be eliminated.
   // See https://crbug.com/647754.
-  HTTP_SHOW_WARNING = 1,
+  // DEPRECATED: Use WARNING instead in most cases.
+  // HTTP_SHOW_WARNING = 1,
 
   // HTTPS with valid EV cert.
   EV_SECURE = 2,
@@ -69,6 +71,11 @@
   // serious security issue that could be dangerous.
   DANGEROUS = 5,
 
+  // Pages deemed insecure, where we should show a warning indicator. This
+  // includes HTTP pages (previously these were HTTP_SHOW_WARNING) and cases
+  // where we consider an HTTPS page to be insecure (e.g., legacy TLS versions).
+  WARNING = 6,
+
   SECURITY_LEVEL_COUNT
 };
 
diff --git a/components/security_state/core/security_state_unittest.cc b/components/security_state/core/security_state_unittest.cc
index 24fa5179..af0a2b3 100644
--- a/components/security_state/core/security_state_unittest.cc
+++ b/components/security_state/core/security_state_unittest.cc
@@ -224,27 +224,27 @@
   EXPECT_EQ(DANGEROUS, helper.GetSecurityLevel());
 }
 
-// Tests that pseudo URLs always cause an HTTP_SHOW_WARNING to be shown.
+// Tests that pseudo URLs always cause an WARNING to be shown.
 TEST(SecurityStateTest, AlwaysWarnOnDataUrls) {
   TestSecurityStateHelper helper;
   helper.SetUrl(GURL(kDataUrl));
-  EXPECT_EQ(HTTP_SHOW_WARNING, helper.GetSecurityLevel());
+  EXPECT_EQ(WARNING, helper.GetSecurityLevel());
 }
 
-// Tests that FTP URLs always cause an HTTP_SHOW_WARNING to be shown.
+// Tests that FTP URLs always cause an WARNING to be shown.
 TEST(SecurityStateTest, AlwaysWarnOnFtpUrls) {
   TestSecurityStateHelper helper;
   helper.SetUrl(GURL(kFtpUrl));
-  EXPECT_EQ(HTTP_SHOW_WARNING, helper.GetSecurityLevel());
+  EXPECT_EQ(WARNING, helper.GetSecurityLevel());
 }
 
-// Tests that the security level is downgraded to HTTP_SHOW_WARNING on pseudo
-// URLs.
+// Tests that the security level is downgraded to WARNING on
+// pseudo URLs.
 TEST(SecurityStateTest, WarningOnPseudoUrls) {
   for (const char* const url : kPseudoUrls) {
     TestSecurityStateHelper helper;
     helper.SetUrl(GURL(url));
-    EXPECT_EQ(HTTP_SHOW_WARNING, helper.GetSecurityLevel());
+    EXPECT_EQ(WARNING, helper.GetSecurityLevel());
   }
 }
 
@@ -308,7 +308,7 @@
   EXPECT_EQ(DANGEROUS, helper.GetSecurityLevel());
 }
 
-// Tests that HTTP_SHOW_WARNING is set on normal http pages but DANGEROUS on
+// Tests that WARNING is set on normal http pages but DANGEROUS on
 // form edits with default feature enabled.
 TEST(SecurityStateTest, WarningAndDangerousOnFormEditsWhenFeatureEnabled) {
   TestSecurityStateHelper helper;
@@ -317,13 +317,13 @@
   scoped_feature_list.InitAndEnableFeature(
       security_state::features::kMarkHttpAsFeature);
 
-  EXPECT_EQ(security_state::HTTP_SHOW_WARNING, helper.GetSecurityLevel());
+  EXPECT_EQ(security_state::WARNING, helper.GetSecurityLevel());
 
   helper.set_insecure_field_edit(true);
   EXPECT_EQ(DANGEROUS, helper.GetSecurityLevel());
 }
 
-// Tests that HTTP_SHOW_WARNING is set on normal http pages but DANGEROUS on
+// Tests that WARNING is set on normal http pages but DANGEROUS on
 // form edits with default feature disabled.
 TEST(SecurityStateTest, WarningAndDangerousOnFormEditsWhenFeatureDisabled) {
   TestSecurityStateHelper helper;
@@ -332,7 +332,7 @@
   scoped_feature_list.InitAndDisableFeature(
       security_state::features::kMarkHttpAsFeature);
 
-  EXPECT_EQ(HTTP_SHOW_WARNING, helper.GetSecurityLevel());
+  EXPECT_EQ(WARNING, helper.GetSecurityLevel());
 
   helper.set_insecure_field_edit(true);
   EXPECT_EQ(DANGEROUS, helper.GetSecurityLevel());
@@ -383,10 +383,10 @@
 
   EXPECT_FALSE(IsSslCertificateValid(SecurityLevel::NONE));
   EXPECT_FALSE(IsSslCertificateValid(SecurityLevel::DANGEROUS));
-  EXPECT_FALSE(IsSslCertificateValid(SecurityLevel::HTTP_SHOW_WARNING));
+  EXPECT_FALSE(IsSslCertificateValid(SecurityLevel::WARNING));
 }
 
-// Tests that HTTP_SHOW_WARNING is not set for error pages.
+// Tests that WARNING is not set for error pages.
 TEST(SecurityStateTest, ErrorPage) {
   TestSecurityStateHelper helper;
   helper.SetUrl(GURL("http://nonexistent.test"));
@@ -396,7 +396,7 @@
   // Sanity-check that if it's not an error page, the security level is
   // downgraded.
   helper.set_is_error_page(false);
-  EXPECT_EQ(SecurityLevel::HTTP_SHOW_WARNING, helper.GetSecurityLevel());
+  EXPECT_EQ(SecurityLevel::WARNING, helper.GetSecurityLevel());
 }
 
 // Tests that the billing status is set, and it overrides valid HTTPS.
@@ -420,7 +420,7 @@
   helper.SetUrl(GURL(kHttpUrl));
 
   // Expect to see a warning for HTTP first.
-  EXPECT_EQ(security_state::HTTP_SHOW_WARNING, helper.GetSecurityLevel());
+  EXPECT_EQ(security_state::WARNING, helper.GetSecurityLevel());
 
   // Now mark the URL as matching the billing list.
   helper.set_malicious_content_status(MALICIOUS_CONTENT_STATUS_BILLING);
diff --git a/components/signin/internal/identity_manager/account_tracker_service_unittest.cc b/components/signin/internal/identity_manager/account_tracker_service_unittest.cc
index 18ca474..00288b8 100644
--- a/components/signin/internal/identity_manager/account_tracker_service_unittest.cc
+++ b/components/signin/internal/identity_manager/account_tracker_service_unittest.cc
@@ -379,7 +379,7 @@
   while (GetTestURLLoaderFactory()->IsPending(url.spec())) {
     GetTestURLLoaderFactory()->SimulateResponseForPendingRequest(
         url, network::URLLoaderCompletionStatus(net::OK),
-        network::CreateResourceResponseHead(response_code), response_string,
+        network::CreateURLResponseHead(response_code), response_string,
         network::TestURLLoaderFactory::kMostRecentMatch);
   }
 }
diff --git a/components/signin/internal/identity_manager/profile_oauth2_token_service_unittest.cc b/components/signin/internal/identity_manager/profile_oauth2_token_service_unittest.cc
index 3142113..7c40287b 100644
--- a/components/signin/internal/identity_manager/profile_oauth2_token_service_unittest.cc
+++ b/components/signin/internal/identity_manager/profile_oauth2_token_service_unittest.cc
@@ -423,11 +423,10 @@
   base::RunLoop().RunUntilIdle();
 
   network::URLLoaderCompletionStatus ok_status(net::OK);
-  network::ResourceResponseHead response_head =
-      network::CreateResourceResponseHead(net::HTTP_OK);
+  auto response_head = network::CreateURLResponseHead(net::HTTP_OK);
   EXPECT_TRUE(test_url_loader_factory_->SimulateResponseForPendingRequest(
-      GaiaUrls::GetInstance()->oauth2_token_url(), ok_status, response_head,
-      GetValidTokenResponse("second token", 3600),
+      GaiaUrls::GetInstance()->oauth2_token_url(), ok_status,
+      std::move(response_head), GetValidTokenResponse("second token", 3600),
       network::TestURLLoaderFactory::kMostRecentMatch));
   EXPECT_EQ(1, consumer2.number_of_successful_tokens_);
   EXPECT_EQ(0, consumer2.number_of_errors_);
@@ -498,11 +497,10 @@
 
   base::RunLoop().RunUntilIdle();
   network::URLLoaderCompletionStatus ok_status(net::OK);
-  network::ResourceResponseHead response_head =
-      network::CreateResourceResponseHead(net::HTTP_OK);
+  auto response_head = network::CreateURLResponseHead(net::HTTP_OK);
   EXPECT_TRUE(test_url_loader_factory_->SimulateResponseForPendingRequest(
-      GaiaUrls::GetInstance()->oauth2_token_url(), ok_status, response_head,
-      GetValidTokenResponse("second token", 3600),
+      GaiaUrls::GetInstance()->oauth2_token_url(), ok_status,
+      std::move(response_head), GetValidTokenResponse("second token", 3600),
       network::TestURLLoaderFactory::kMostRecentMatch));
   EXPECT_EQ(1, consumer_.number_of_successful_tokens_);
   EXPECT_EQ(0, consumer_.number_of_errors_);
diff --git a/components/suggestions/suggestions_service_impl_unittest.cc b/components/suggestions/suggestions_service_impl_unittest.cc
index 9ac6c86..95e71cd 100644
--- a/components/suggestions/suggestions_service_impl_unittest.cc
+++ b/components/suggestions/suggestions_service_impl_unittest.cc
@@ -170,7 +170,7 @@
                       int net_error = net::OK) {
     bool rv = url_loader_factory()->SimulateResponseForPendingRequest(
         url, network::URLLoaderCompletionStatus(net_error),
-        network::CreateResourceResponseHead(response_code), response_body);
+        network::CreateURLResponseHead(response_code), response_body);
     task_environment_.RunUntilIdle();
     return rv;
   }
diff --git a/components/test/run_all_unittests.cc b/components/test/run_all_unittests.cc
index 92af0b5..5f8b3ae 100644
--- a/components/test/run_all_unittests.cc
+++ b/components/test/run_all_unittests.cc
@@ -5,5 +5,5 @@
 #include "components/test/components_test_suite.h"
 
 int main(int argc, char** argv) {
-  return base::LaunchUnitTests(argc, argv, GetLaunchCallback(argc, argv));
+  return base::LaunchUnitTests(argc, argv, GetLaunchCallback(argc, argv), 0U);
 }
diff --git a/components/update_client/crx_downloader_unittest.cc b/components/update_client/crx_downloader_unittest.cc
index 08e6794f..62082fd 100644
--- a/components/update_client/crx_downloader_unittest.cc
+++ b/components/update_client/crx_downloader_unittest.cc
@@ -158,17 +158,17 @@
   if (net_error == net::OK) {
     std::string data;
     EXPECT_TRUE(base::ReadFileToString(file_path, &data));
-    network::ResourceResponseHead head;
-    head.content_length = data.size();
+    auto head = network::mojom::URLResponseHead::New();
+    head->content_length = data.size();
     network::URLLoaderCompletionStatus status(net_error);
     status.decoded_body_length = data.size();
-    test_url_loader_factory_.AddResponse(url, head, data, status);
+    test_url_loader_factory_.AddResponse(url, std::move(head), data, status);
     return;
   }
 
   EXPECT_NE(net_error, net::OK);
   test_url_loader_factory_.AddResponse(
-      url, network::ResourceResponseHead(), std::string(),
+      url, network::mojom::URLResponseHead::New(), std::string(),
       network::URLLoaderCompletionStatus(net_error));
 }
 
diff --git a/components/variations/service/variations_service_unittest.cc b/components/variations/service/variations_service_unittest.cc
index 8d451556..bf7612c 100644
--- a/components/variations/service/variations_service_unittest.cc
+++ b/components/variations/service/variations_service_unittest.cc
@@ -559,15 +559,15 @@
     service.set_intercepts_fetch(false);
 
     std::string headers("HTTP/1.1 200 OK\n\n");
-    network::ResourceResponseHead head;
-    head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+    auto head = network::mojom::URLResponseHead::New();
+    head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
         net::HttpUtil::AssembleRawHeaders(headers));
     if (!cases[i].im.empty())
-      head.headers->AddHeader(cases[i].im);
+      head->headers->AddHeader(cases[i].im);
     network::URLLoaderCompletionStatus status;
     status.decoded_body_length = serialized_seed.size();
     service.test_url_loader_factory()->AddResponse(
-        service.interception_url(), head, serialized_seed, status);
+        service.interception_url(), std::move(head), serialized_seed, status);
 
     service.DoActualFetch();
 
@@ -589,14 +589,14 @@
   service.set_intercepts_fetch(false);
 
   std::string headers("HTTP/1.1 200 OK\n\n");
-  network::ResourceResponseHead head;
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+  auto head = network::mojom::URLResponseHead::New();
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
       net::HttpUtil::AssembleRawHeaders(headers));
-  head.headers->AddHeader("X-Country: test");
+  head->headers->AddHeader("X-Country: test");
   network::URLLoaderCompletionStatus status;
   status.decoded_body_length = serialized_seed.size();
-  service.test_url_loader_factory()->AddResponse(service.interception_url(),
-                                                 head, serialized_seed, status);
+  service.test_url_loader_factory()->AddResponse(
+      service.interception_url(), std::move(head), serialized_seed, status);
 
   service.DoActualFetch();
 
@@ -897,14 +897,14 @@
       std::string("X-Seed-Signature:") + kBase64SeedSignature;
 
   std::string headers("HTTP/1.1 200 OK\n\n");
-  network::ResourceResponseHead head;
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+  auto head = network::mojom::URLResponseHead::New();
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
       net::HttpUtil::AssembleRawHeaders(headers));
-  head.headers->AddHeader(seed_signature_header);
+  head->headers->AddHeader(seed_signature_header);
   network::URLLoaderCompletionStatus status;
   status.decoded_body_length = response.size();
-  service.test_url_loader_factory()->AddResponse(service.interception_url(),
-                                                 head, response, status);
+  service.test_url_loader_factory()->AddResponse(
+      service.interception_url(), std::move(head), response, status);
 
   service.DoActualFetch();
 
@@ -927,12 +927,12 @@
   service.set_intercepts_fetch(false);
 
   std::string headers("HTTP/1.1 304 Not Modified\n\n");
-  network::ResourceResponseHead head;
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+  auto head = network::mojom::URLResponseHead::New();
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
       net::HttpUtil::AssembleRawHeaders(headers));
   network::URLLoaderCompletionStatus status;
   service.test_url_loader_factory()->AddResponse(service.interception_url(),
-                                                 head, "", status);
+                                                 std::move(head), "", status);
 
   service.DoActualFetch();
 
@@ -1037,15 +1037,15 @@
   net::RedirectInfo redirect_info;
   redirect_info.status_code = 301;
   redirect_info.new_url = service.interception_url();
-  network::TestURLLoaderFactory::Redirects redirects{
-      {redirect_info, network::ResourceResponseHead()}};
+  network::TestURLLoaderFactory::Redirects redirects;
+  redirects.push_back({redirect_info, network::mojom::URLResponseHead::New()});
 
-  network::ResourceResponseHead head =
-      network::CreateResourceResponseHead(net::HTTP_OK);
+  auto head = network::CreateURLResponseHead(net::HTTP_OK);
 
   service.test_url_loader_factory()->AddResponse(
-      service.interception_url(), head, SerializeSeed(CreateTestSeed()),
-      network::URLLoaderCompletionStatus(), redirects);
+      service.interception_url(), std::move(head),
+      SerializeSeed(CreateTestSeed()), network::URLLoaderCompletionStatus(),
+      std::move(redirects));
 
   service.set_intercepts_fetch(false);
   service.DoActualFetch();
@@ -1067,20 +1067,21 @@
       std::string("X-Seed-Signature:") + kBase64SeedSignature;
 
   std::string headers("HTTP/1.1 200 OK\n\n");
-  network::ResourceResponseHead head;
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+  auto head = network::mojom::URLResponseHead::New();
+  auto http_response_headers = base::MakeRefCounted<net::HttpResponseHeaders>(
       net::HttpUtil::AssembleRawHeaders(headers));
-  EXPECT_EQ(net::HTTP_OK, head.headers->response_code());
-  head.headers->AddHeader(seed_signature_header);
+  head->headers = http_response_headers;
+  EXPECT_EQ(net::HTTP_OK, http_response_headers->response_code());
+  http_response_headers->AddHeader(seed_signature_header);
   // Set ERR_FAILED status code despite the 200 response code.
   network::URLLoaderCompletionStatus status(net::ERR_FAILED);
   status.decoded_body_length = response.size();
   service.test_url_loader_factory()->AddResponse(
-      service.interception_url(), head, response, status,
+      service.interception_url(), std::move(head), response, status,
       network::TestURLLoaderFactory::Redirects(),
       // We pass the flag below to preserve the 200 code with an error response.
       network::TestURLLoaderFactory::kSendHeadersOnNetworkError);
-  EXPECT_EQ(net::HTTP_OK, head.headers->response_code());
+  EXPECT_EQ(net::HTTP_OK, http_response_headers->response_code());
 
   base::HistogramTester histogram_tester;
   service.DoActualFetch();
diff --git a/components/viz/common/quads/stream_video_draw_quad.cc b/components/viz/common/quads/stream_video_draw_quad.cc
index bf1eae9..57f3fee 100644
--- a/components/viz/common/quads/stream_video_draw_quad.cc
+++ b/components/viz/common/quads/stream_video_draw_quad.cc
@@ -16,16 +16,14 @@
 StreamVideoDrawQuad::StreamVideoDrawQuad(const StreamVideoDrawQuad& quad) =
     default;
 
-void StreamVideoDrawQuad::SetNew(
-    const SharedQuadState* shared_quad_state,
-    const gfx::Rect& rect,
-    const gfx::Rect& visible_rect,
-    bool needs_blending,
-    unsigned resource_id,
-    gfx::Size resource_size_in_pixels,
-    const gfx::PointF& uv_top_left,
-    const gfx::PointF& uv_bottom_right,
-    const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info) {
+void StreamVideoDrawQuad::SetNew(const SharedQuadState* shared_quad_state,
+                                 const gfx::Rect& rect,
+                                 const gfx::Rect& visible_rect,
+                                 bool needs_blending,
+                                 unsigned resource_id,
+                                 gfx::Size resource_size_in_pixels,
+                                 const gfx::PointF& uv_top_left,
+                                 const gfx::PointF& uv_bottom_right) {
   DrawQuad::SetAll(shared_quad_state, DrawQuad::Material::kStreamVideoContent,
                    rect, visible_rect, needs_blending);
   resources.ids[kResourceIdIndex] = resource_id;
@@ -33,7 +31,6 @@
   resources.count = 1;
   this->uv_top_left = uv_top_left;
   this->uv_bottom_right = uv_bottom_right;
-  this->ycbcr_info = ycbcr_info;
 }
 
 void StreamVideoDrawQuad::SetAll(const SharedQuadState* shared_quad_state,
diff --git a/components/viz/common/quads/stream_video_draw_quad.h b/components/viz/common/quads/stream_video_draw_quad.h
index 3e67e7a..a35bda2 100644
--- a/components/viz/common/quads/stream_video_draw_quad.h
+++ b/components/viz/common/quads/stream_video_draw_quad.h
@@ -24,16 +24,14 @@
   ~StreamVideoDrawQuad() override;
   StreamVideoDrawQuad(const StreamVideoDrawQuad& quad);
 
-  void SetNew(
-      const SharedQuadState* shared_quad_state,
-      const gfx::Rect& rect,
-      const gfx::Rect& visible_rect,
-      bool needs_blending,
-      unsigned resource_id,
-      gfx::Size resource_size_in_pixels,
-      const gfx::PointF& uv_top_left,
-      const gfx::PointF& uv_bottom_right,
-      const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info = base::nullopt);
+  void SetNew(const SharedQuadState* shared_quad_state,
+              const gfx::Rect& rect,
+              const gfx::Rect& visible_rect,
+              bool needs_blending,
+              unsigned resource_id,
+              gfx::Size resource_size_in_pixels,
+              const gfx::PointF& uv_top_left,
+              const gfx::PointF& uv_bottom_right);
 
   void SetAll(const SharedQuadState* shared_quad_state,
               const gfx::Rect& rect,
@@ -53,9 +51,6 @@
   };
   OverlayResources overlay_resources;
 
-  // Sampler conversion information which is used in vulkan context for android.
-  base::Optional<gpu::VulkanYCbCrInfo> ycbcr_info;
-
   static const StreamVideoDrawQuad* MaterialCast(const DrawQuad*);
 
   ResourceId resource_id() const { return resources.ids[kResourceIdIndex]; }
diff --git a/components/viz/common/resources/DEPS b/components/viz/common/resources/DEPS
index d6e39ea..972774c 100644
--- a/components/viz/common/resources/DEPS
+++ b/components/viz/common/resources/DEPS
@@ -5,6 +5,7 @@
   # cc::MathUtil. Remove it once cc/base/math_util* are moved to viz.
   "+cc/base",
   "+gpu/command_buffer/common",
+  "+gpu/ipc/common",
   "+gpu/vulkan/buildflags.h",
   "+gpu/GLES2",
   "+mojo/public/cpp/system/buffer.h",
diff --git a/components/viz/common/resources/resource_format_utils.cc b/components/viz/common/resources/resource_format_utils.cc
index f85db98..cdb55054e 100644
--- a/components/viz/common/resources/resource_format_utils.cc
+++ b/components/viz/common/resources/resource_format_utils.cc
@@ -23,7 +23,6 @@
     return kN32_SkColorType;
   }
 
-  // Use kN32_SkColorType if there is no corresponding SkColorType.
   switch (format) {
     case RGBA_4444:
       return kARGB_4444_SkColorType;
@@ -40,6 +39,13 @@
     case RGBX_8888:
     case ETC1:
       return kRGB_888x_SkColorType;
+
+    // YUV images are sampled as RGB.
+    case YVU_420:
+    case YUV_420_BIPLANAR:
+      return kRGB_888x_SkColorType;
+
+    // Use kN32_SkColorType if there is no corresponding SkColorType.
     case RED_8:
       return kGray_8_SkColorType;
     case LUMINANCE_F16:
@@ -49,10 +55,9 @@
     case BGRX_8888:
     case RGBX_1010102:
     case BGRX_1010102:
-    case YVU_420:
-    case YUV_420_BIPLANAR:
     case P010:
       return kN32_SkColorType;
+
     case RGBA_F16:
       return kRGBA_F16_SkColorType;
   }
diff --git a/components/viz/common/resources/transferable_resource.h b/components/viz/common/resources/transferable_resource.h
index e6547e7..1f3c93e 100644
--- a/components/viz/common/resources/transferable_resource.h
+++ b/components/viz/common/resources/transferable_resource.h
@@ -15,6 +15,7 @@
 #include "components/viz/common/resources/shared_bitmap.h"
 #include "components/viz/common/viz_common_export.h"
 #include "gpu/command_buffer/common/mailbox_holder.h"
+#include "gpu/ipc/common/vulkan_ycbcr_info.h"
 #include "ui/gfx/buffer_types.h"
 #include "ui/gfx/color_space.h"
 #include "ui/gfx/geometry/size.h"
@@ -104,6 +105,10 @@
   // out-of-band, and a gpu fence needs to be waited on before the resource is
   // returned and reused.
   bool read_lock_fences_enabled = false;
+
+  // YCbCr info for resources backed by YCbCr Vulkan images.
+  base::Optional<gpu::VulkanYCbCrInfo> ycbcr_info;
+
 #if defined(OS_ANDROID)
   // Indicates whether this resource may not be overlayed on Android, since
   // it's not backed by a SurfaceView.  This may be set in combination with
diff --git a/components/viz/service/display/display_resource_provider.cc b/components/viz/service/display/display_resource_provider.cc
index a106fbc..855df6c 100644
--- a/components/viz/service/display/display_resource_provider.cc
+++ b/components/viz/service/display/display_resource_provider.cc
@@ -927,7 +927,7 @@
       resource.image_context =
           resource_provider_->external_use_client_->CreateImageContext(
               resource.transferable.mailbox_holder, resource.transferable.size,
-              resource.transferable.format,
+              resource.transferable.format, resource.transferable.ycbcr_info,
               // The resource |color_space| is ignored by SkiaRenderer for video
               // planes and usually cannot be converted to SkColorSpace.
               is_video_plane
diff --git a/components/viz/service/display/display_resource_provider_unittest.cc b/components/viz/service/display/display_resource_provider_unittest.cc
index 29109fd..6705ded 100644
--- a/components/viz/service/display/display_resource_provider_unittest.cc
+++ b/components/viz/service/display/display_resource_provider_unittest.cc
@@ -231,11 +231,13 @@
   MockExternalUseClient() = default;
   MOCK_METHOD1(ReleaseImageContexts,
                void(std::vector<std::unique_ptr<ImageContext>> image_contexts));
-  MOCK_METHOD4(CreateImageContext,
-               std::unique_ptr<ImageContext>(const gpu::MailboxHolder&,
-                                             const gfx::Size&,
-                                             ResourceFormat,
-                                             sk_sp<SkColorSpace>));
+  MOCK_METHOD5(CreateImageContext,
+               std::unique_ptr<ImageContext>(
+                   const gpu::MailboxHolder&,
+                   const gfx::Size&,
+                   ResourceFormat,
+                   const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info,
+                   sk_sp<SkColorSpace>));
 };
 
 TEST_P(DisplayResourceProviderTest, LockForExternalUse) {
@@ -275,14 +277,14 @@
 
   auto owned_image_context = std::make_unique<ExternalUseClient::ImageContext>(
       gpu::MailboxHolder(mailbox, sync_token1, GL_TEXTURE_2D), size, RGBA_8888,
-      /*color_space=*/nullptr);
+      /*ycbcr_info=*/base::nullopt, /*color_space=*/nullptr);
   auto* image_context = owned_image_context.get();
 
   testing::StrictMock<MockExternalUseClient> client;
   DisplayResourceProvider::LockSetForExternalUse lock_set(
       resource_provider_.get(), &client);
   gpu::MailboxHolder holder;
-  EXPECT_CALL(client, CreateImageContext(_, _, _, _))
+  EXPECT_CALL(client, CreateImageContext(_, _, _, _, _))
       .WillOnce(DoAll(SaveArg<0>(&holder),
                       Return(ByMove(std::move(owned_image_context)))));
 
diff --git a/components/viz/service/display/external_use_client.cc b/components/viz/service/display/external_use_client.cc
index e9a2297..5ea946ee 100644
--- a/components/viz/service/display/external_use_client.cc
+++ b/components/viz/service/display/external_use_client.cc
@@ -10,11 +10,13 @@
     const gpu::MailboxHolder& mailbox_holder,
     const gfx::Size& size,
     ResourceFormat resource_format,
+    const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info,
     sk_sp<SkColorSpace> color_space)
     : mailbox_holder_(mailbox_holder),
       size_(size),
       resource_format_(resource_format),
-      color_space_(std::move(color_space)) {}
+      color_space_(std::move(color_space)),
+      ycbcr_info_(ycbcr_info) {}
 
 ExternalUseClient::ImageContext::~ImageContext() = default;
 
diff --git a/components/viz/service/display/external_use_client.h b/components/viz/service/display/external_use_client.h
index 288aca3..de2dd34 100644
--- a/components/viz/service/display/external_use_client.h
+++ b/components/viz/service/display/external_use_client.h
@@ -35,6 +35,7 @@
     ImageContext(const gpu::MailboxHolder& mailbox_holder,
                  const gfx::Size& size,
                  ResourceFormat resource_format,
+                 const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info,
                  sk_sp<SkColorSpace> color_space);
     virtual ~ImageContext();
 
@@ -63,11 +64,6 @@
     }
 
     base::Optional<gpu::VulkanYCbCrInfo> ycbcr_info() { return ycbcr_info_; }
-    void set_ycbcr_info(
-        const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info) {
-      DCHECK(!image_);
-      ycbcr_info_ = ycbcr_info;
-    }
 
     bool has_image() { return !!image_; }
     sk_sp<SkImage> image() { return image_; }
@@ -100,6 +96,7 @@
       const gpu::MailboxHolder& holder,
       const gfx::Size& size,
       ResourceFormat format,
+      const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info,
       sk_sp<SkColorSpace> color_space) = 0;
 
   virtual void ReleaseImageContexts(
diff --git a/components/viz/service/display/skia_renderer.cc b/components/viz/service/display/skia_renderer.cc
index b34d2f6..d0f6e08 100644
--- a/components/viz/service/display/skia_renderer.cc
+++ b/components/viz/service/display/skia_renderer.cc
@@ -459,11 +459,6 @@
                        ResourceId resource_id,
                        SkAlphaType alpha_type = kPremul_SkAlphaType,
                        GrSurfaceOrigin origin = kTopLeft_GrSurfaceOrigin);
-  ScopedSkImageBuilder(SkiaRenderer* skia_renderer,
-                       ResourceId resource_id,
-                       base::Optional<gpu::VulkanYCbCrInfo> ycbcr_info,
-                       SkAlphaType alpha_type = kPremul_SkAlphaType,
-                       GrSurfaceOrigin origin = kTopLeft_GrSurfaceOrigin);
   ~ScopedSkImageBuilder() = default;
 
   const SkImage* sk_image() const { return sk_image_; }
@@ -479,18 +474,6 @@
     SkiaRenderer* skia_renderer,
     ResourceId resource_id,
     SkAlphaType alpha_type,
-    GrSurfaceOrigin origin)
-    : SkiaRenderer::ScopedSkImageBuilder(skia_renderer,
-                                         resource_id,
-                                         base::nullopt,
-                                         alpha_type,
-                                         origin) {}
-
-SkiaRenderer::ScopedSkImageBuilder::ScopedSkImageBuilder(
-    SkiaRenderer* skia_renderer,
-    ResourceId resource_id,
-    base::Optional<gpu::VulkanYCbCrInfo> ycbcr_info,
-    SkAlphaType alpha_type,
     GrSurfaceOrigin origin) {
   if (!resource_id)
     return;
@@ -510,7 +493,6 @@
     if (!image_context->has_image()) {
       image_context->set_alpha_type(alpha_type);
       image_context->set_origin(origin);
-      image_context->set_ycbcr_info(ycbcr_info);
     }
     skia_renderer->skia_output_surface_->MakePromiseSkImage(image_context);
     LOG_IF(ERROR, !image_context->has_image())
@@ -1312,7 +1294,7 @@
                                        DrawQuadParams* params) {
   DCHECK(!MustFlushBatchedQuads(quad, *params));
 
-  ScopedSkImageBuilder builder(this, quad->resource_id(), quad->ycbcr_info,
+  ScopedSkImageBuilder builder(this, quad->resource_id(),
                                kUnpremul_SkAlphaType);
   const SkImage* image = builder.sk_image();
   if (!image)
diff --git a/components/viz/service/display_embedder/image_context_impl.cc b/components/viz/service/display_embedder/image_context_impl.cc
index e98cae3..bada876 100644
--- a/components/viz/service/display_embedder/image_context_impl.cc
+++ b/components/viz/service/display_embedder/image_context_impl.cc
@@ -17,11 +17,17 @@
 
 namespace viz {
 
-ImageContextImpl::ImageContextImpl(const gpu::MailboxHolder& mailbox_holder,
-                                   const gfx::Size& size,
-                                   ResourceFormat resource_format,
-                                   sk_sp<SkColorSpace> color_space)
-    : ImageContext(mailbox_holder, size, resource_format, color_space) {}
+ImageContextImpl::ImageContextImpl(
+    const gpu::MailboxHolder& mailbox_holder,
+    const gfx::Size& size,
+    ResourceFormat resource_format,
+    const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info,
+    sk_sp<SkColorSpace> color_space)
+    : ImageContext(mailbox_holder,
+                   size,
+                   resource_format,
+                   ycbcr_info,
+                   color_space) {}
 
 ImageContextImpl::ImageContextImpl(RenderPassId render_pass_id,
                                    const gfx::Size& size,
@@ -31,6 +37,7 @@
     : ImageContext(gpu::MailboxHolder(),
                    size,
                    resource_format,
+                   /*ycbcr_info=*/base::nullopt,
                    std::move(color_space)),
       render_pass_id_(render_pass_id),
       mipmap_(mipmap ? GrMipMapped::kYes : GrMipMapped::kNo) {}
diff --git a/components/viz/service/display_embedder/image_context_impl.h b/components/viz/service/display_embedder/image_context_impl.h
index 6fd6059..8d661b4 100644
--- a/components/viz/service/display_embedder/image_context_impl.h
+++ b/components/viz/service/display_embedder/image_context_impl.h
@@ -44,6 +44,7 @@
   ImageContextImpl(const gpu::MailboxHolder& mailbox_holder,
                    const gfx::Size& size,
                    ResourceFormat resource_format,
+                   const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info,
                    sk_sp<SkColorSpace> color_space);
 
   // TODO(https://crbug.com/991659): The use of ImageContext for
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.cc b/components/viz/service/display_embedder/skia_output_surface_impl.cc
index b9ca2cb..56eadec 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl.cc
+++ b/components/viz/service/display_embedder/skia_output_surface_impl.cc
@@ -34,6 +34,11 @@
 #include "ui/gl/gl_context.h"
 #include "ui/gl/gl_gl_api_implementation.h"
 
+#if BUILDFLAG(ENABLE_VULKAN)
+#include "components/viz/common/gpu/vulkan_context_provider.h"
+#include "gpu/vulkan/vulkan_device_queue.h"
+#endif  // BUILDFLAG(ENABLE_VULKAN)
+
 namespace viz {
 
 namespace {
@@ -327,7 +332,8 @@
     auto* context = static_cast<ImageContextImpl*>(contexts[i]);
     DCHECK(context->origin() == kTopLeft_GrSurfaceOrigin);
     formats[i] = GetGrBackendFormatForTexture(
-        context->resource_format(), context->mailbox_holder().texture_target);
+        context->resource_format(), context->mailbox_holder().texture_target,
+        /*ycbcr_info=*/base::nullopt);
     yuva_sizes[i].set(context->size().width(), context->size().height());
 
     // NOTE: We don't have promises for individual planes, but still need format
@@ -365,11 +371,13 @@
 }
 
 std::unique_ptr<ExternalUseClient::ImageContext>
-SkiaOutputSurfaceImpl::CreateImageContext(const gpu::MailboxHolder& holder,
-                                          const gfx::Size& size,
-                                          ResourceFormat format,
-                                          sk_sp<SkColorSpace> color_space) {
-  return std::make_unique<ImageContextImpl>(holder, size, format,
+SkiaOutputSurfaceImpl::CreateImageContext(
+    const gpu::MailboxHolder& holder,
+    const gfx::Size& size,
+    ResourceFormat format,
+    const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info,
+    sk_sp<SkColorSpace> color_space) {
+  return std::make_unique<ImageContextImpl>(holder, size, format, ycbcr_info,
                                             std::move(color_space));
 }
 
@@ -505,8 +513,8 @@
   if (!image_context->has_image()) {
     SkColorType color_type =
         ResourceFormatToClosestSkColorType(true /* gpu_compositing */, format);
-    GrBackendFormat backend_format =
-        GetGrBackendFormatForTexture(format, GL_TEXTURE_2D);
+    GrBackendFormat backend_format = GetGrBackendFormatForTexture(
+        format, GL_TEXTURE_2D, /*ycbcr_info=*/base::nullopt);
     image_context->SetImage(
         current_paint_->recorder()->makePromiseTexture(
             backend_format, image_context->size().width(),
@@ -721,7 +729,7 @@
 GrBackendFormat SkiaOutputSurfaceImpl::GetGrBackendFormatForTexture(
     ResourceFormat resource_format,
     uint32_t gl_texture_target,
-    base::Optional<gpu::VulkanYCbCrInfo> ycbcr_info) {
+    const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info) {
   if (!is_using_vulkan_) {
     DCHECK(!ycbcr_info);
     // Convert internal format from GLES2 to platform GL.
@@ -731,21 +739,18 @@
     return GrBackendFormat::MakeGL(texture_storage_format, gl_texture_target);
   } else {
 #if BUILDFLAG(ENABLE_VULKAN)
-    if (!ycbcr_info)
+    if (!ycbcr_info) {
+      // YCbCr info is required for YUV images.
+      DCHECK(resource_format != YVU_420 && resource_format != YUV_420_BIPLANAR);
       return GrBackendFormat::MakeVk(ToVkFormat(resource_format));
+    }
 
-    VkFormat format = ycbcr_info->external_format ? VK_FORMAT_UNDEFINED
-                                                  : ToVkFormat(resource_format);
-    GrVkYcbcrConversionInfo gr_ycbcr_info(
-        format, ycbcr_info->external_format,
-        static_cast<VkSamplerYcbcrModelConversion>(
-            ycbcr_info->suggested_ycbcr_model),
-        static_cast<VkSamplerYcbcrRange>(ycbcr_info->suggested_ycbcr_range),
-        static_cast<VkChromaLocation>(ycbcr_info->suggested_xchroma_offset),
-        static_cast<VkChromaLocation>(ycbcr_info->suggested_ychroma_offset),
-        VK_FILTER_LINEAR,  // VkFilter
-        0,                 // VkBool32 forceExplicitReconstruction,
-        static_cast<VkFormatFeatureFlags>(ycbcr_info->format_features));
+    // Assume optimal tiling.
+    GrVkYcbcrConversionInfo gr_ycbcr_info =
+        CreateGrVkYcbcrConversionInfo(dependency_->GetVulkanContextProvider()
+                                          ->GetDeviceQueue()
+                                          ->GetVulkanPhysicalDevice(),
+                                      VK_IMAGE_TILING_OPTIMAL, ycbcr_info);
     return GrBackendFormat::MakeVk(gr_ycbcr_info);
 #else
     NOTREACHED();
diff --git a/components/viz/service/display_embedder/skia_output_surface_impl.h b/components/viz/service/display_embedder/skia_output_surface_impl.h
index fb5a713..1590413 100644
--- a/components/viz/service/display_embedder/skia_output_surface_impl.h
+++ b/components/viz/service/display_embedder/skia_output_surface_impl.h
@@ -130,6 +130,7 @@
       const gpu::MailboxHolder& holder,
       const gfx::Size& size,
       ResourceFormat format,
+      const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info,
       sk_sp<SkColorSpace> color_space) override;
 
   // Set the fields of |capabilities_| and propagates to |impl_on_gpu_|. Should
@@ -161,7 +162,7 @@
   GrBackendFormat GetGrBackendFormatForTexture(
       ResourceFormat resource_format,
       uint32_t gl_texture_target,
-      base::Optional<gpu::VulkanYCbCrInfo> ycbcr_info = base::nullopt);
+      const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info);
   void PrepareYUVATextureIndices(const std::vector<ImageContext*>& contexts,
                                  bool has_alpha,
                                  SkYUVAIndex indices[4]);
diff --git a/components/viz/service/display_embedder/viz_process_context_provider.cc b/components/viz/service/display_embedder/viz_process_context_provider.cc
index 41d744bd..178b453 100644
--- a/components/viz/service/display_embedder/viz_process_context_provider.cc
+++ b/components/viz/service/display_embedder/viz_process_context_provider.cc
@@ -138,7 +138,10 @@
     base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
         this);
   }
-  cache_controller_->SetGrContext(nullptr);
+
+  // cache_controller_ might ne nullptr if we failed to initialize
+  if (cache_controller_)
+    cache_controller_->SetGrContext(nullptr);
 }
 
 void VizProcessContextProvider::AddRef() const {
diff --git a/components/viz/test/fake_skia_output_surface.cc b/components/viz/test/fake_skia_output_surface.cc
index 8573db5..0250b3cd 100644
--- a/components/viz/test/fake_skia_output_surface.cc
+++ b/components/viz/test/fake_skia_output_surface.cc
@@ -177,12 +177,14 @@
     std::vector<std::unique_ptr<ImageContext>> image_contexts) {}
 
 std::unique_ptr<ExternalUseClient::ImageContext>
-FakeSkiaOutputSurface::CreateImageContext(const gpu::MailboxHolder& holder,
-                                          const gfx::Size& size,
-                                          ResourceFormat format,
-                                          sk_sp<SkColorSpace> color_space) {
+FakeSkiaOutputSurface::CreateImageContext(
+    const gpu::MailboxHolder& holder,
+    const gfx::Size& size,
+    ResourceFormat format,
+    const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info,
+    sk_sp<SkColorSpace> color_space) {
   return std::make_unique<ExternalUseClient::ImageContext>(
-      holder, size, format, std::move(color_space));
+      holder, size, format, ycbcr_info, std::move(color_space));
 }
 
 gpu::SyncToken FakeSkiaOutputSurface::SkiaSwapBuffers(OutputSurfaceFrame frame,
diff --git a/components/viz/test/fake_skia_output_surface.h b/components/viz/test/fake_skia_output_surface.h
index 29e2271..0c27b12 100644
--- a/components/viz/test/fake_skia_output_surface.h
+++ b/components/viz/test/fake_skia_output_surface.h
@@ -105,6 +105,7 @@
       const gpu::MailboxHolder& holder,
       const gfx::Size& size,
       ResourceFormat format,
+      const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info,
       sk_sp<SkColorSpace> color_space) override;
 
   // If set true, callbacks triggering will be in a reverse order as SignalQuery
diff --git a/content/browser/appcache/appcache_fuzzer.cc b/content/browser/appcache/appcache_fuzzer.cc
index a31086a1..016cc36 100644
--- a/content/browser/appcache/appcache_fuzzer.cc
+++ b/content/browser/appcache/appcache_fuzzer.cc
@@ -102,7 +102,7 @@
   network::URLLoaderCompletionStatus status;
   status.error_code = net::OK;
 
-  network::ResourceResponseHead response;
+  auto response = network::mojom::URLResponseHead::New();
 
   std::string headers = "HTTP/1.1 ";
   headers += std::to_string(code);
@@ -116,7 +116,7 @@
   }
   HeadersToRaw(&headers);
 
-  response.headers = base::MakeRefCounted<net::HttpResponseHeaders>(headers);
+  response->headers = base::MakeRefCounted<net::HttpResponseHeaders>(headers);
 
   // To simplify the fuzzer, we respond to all requests with a manifest.
   // When we're performing a manifest fetch, this data will affect the
@@ -126,7 +126,7 @@
   content += "\n# ";
 
   factory->SimulateResponseForPendingRequest(
-      GURL(GetUrl(url)), status, response, content,
+      GURL(GetUrl(url)), status, std::move(response), content,
       network::TestURLLoaderFactory::kUrlMatchPrefix);
 }
 
diff --git a/content/browser/blob_storage/blob_url_unittest.cc b/content/browser/blob_storage/blob_url_unittest.cc
index b6124bbe..d226e872 100644
--- a/content/browser/blob_storage/blob_url_unittest.cc
+++ b/content/browser/blob_storage/blob_url_unittest.cc
@@ -216,7 +216,9 @@
       EXPECT_TRUE(mojo::BlockingCopyToString(
           url_loader_client.response_body_release(), &response_));
     }
-    response_headers_ = url_loader_client.response_head().headers;
+    response_headers_ = url_loader_client.response_head()
+                            ? url_loader_client.response_head()->headers
+                            : nullptr;
     response_metadata_ = url_loader_client.cached_metadata();
     response_error_code_ = url_loader_client.completion_status().error_code;
 
diff --git a/content/browser/blob_storage/chrome_blob_storage_context.cc b/content/browser/blob_storage/chrome_blob_storage_context.cc
index d5a80de..7550078 100644
--- a/content/browser/blob_storage/chrome_blob_storage_context.cc
+++ b/content/browser/blob_storage/chrome_blob_storage_context.cc
@@ -217,10 +217,10 @@
       base::BindOnce(
           [](scoped_refptr<ChromeBlobStorageContext> context,
              network::mojom::URLLoaderFactoryRequest request, const GURL& url) {
-            auto blob_handle =
-                context->context()->GetBlobDataFromPublicURL(url);
-            storage::BlobURLLoaderFactory::Create(std::move(blob_handle), url,
-                                                  std::move(request));
+            auto blob_remote = context->context()->GetBlobFromPublicURL(url);
+            storage::BlobURLLoaderFactory::Create(
+                std::move(blob_remote), url, context->context()->AsWeakPtr(),
+                std::move(request));
           },
           base::WrapRefCounted(GetFor(browser_context)),
           MakeRequest(&blob_url_loader_factory_ptr), url));
diff --git a/content/browser/cache_storage/cache_storage_cache_unittest.cc b/content/browser/cache_storage/cache_storage_cache_unittest.cc
index 48a0500d..f05c5d7 100644
--- a/content/browser/cache_storage/cache_storage_cache_unittest.cc
+++ b/content/browser/cache_storage/cache_storage_cache_unittest.cc
@@ -527,7 +527,7 @@
         nullptr /* blob */, blink::mojom::ServiceWorkerResponseError::kUnknown,
         response_time_, std::string() /* cache_storage_cache_name */,
         std::vector<std::string>() /* cors_exposed_header_names */,
-        nullptr /* side_data_blob */);
+        nullptr /* side_data_blob */, nullptr /* content_security_policy */);
   }
 
   std::unique_ptr<storage::BlobDataHandle> BuildBlobHandle(
diff --git a/content/browser/cache_storage/cache_storage_manager_unittest.cc b/content/browser/cache_storage/cache_storage_manager_unittest.cc
index ec3ccbc..d89bcd3 100644
--- a/content/browser/cache_storage/cache_storage_manager_unittest.cc
+++ b/content/browser/cache_storage/cache_storage_manager_unittest.cc
@@ -667,7 +667,7 @@
         std::move(blob), blink::mojom::ServiceWorkerResponseError::kUnknown,
         base::Time(), std::string() /* cache_storage_cache_name */,
         std::vector<std::string>() /* cors_exposed_header_names */,
-        nullptr /* side_data_blob */);
+        nullptr /* side_data_blob */, nullptr /* content_security_policy */);
 
     blink::mojom::BatchOperationPtr operation =
         blink::mojom::BatchOperation::New();
diff --git a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
index 86ee55c..ce9e979 100644
--- a/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
+++ b/content/browser/cache_storage/legacy/legacy_cache_storage_cache.cc
@@ -356,7 +356,7 @@
       std::vector<std::string>(
           metadata.response().cors_exposed_header_names().begin(),
           metadata.response().cors_exposed_header_names().end()),
-      nullptr /* side_data_blob */);
+      nullptr /* side_data_blob */, nullptr /* content_security_policy */);
 }
 
 // The size of opaque (non-cors) resource responses are padded in order
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc
index 0dc44d6..1d9e3e3 100644
--- a/content/browser/child_process_launcher.cc
+++ b/content/browser/child_process_launcher.cc
@@ -186,8 +186,11 @@
 }
 
 bool ChildProcessLauncherPriority::is_background() const {
-  return !visible && !has_media_stream && !boost_for_pending_views &&
-         !has_foreground_service_worker;
+  if (boost_for_pending_views || has_foreground_service_worker ||
+      has_media_stream) {
+    return false;
+  }
+  return has_only_low_priority_frames || !visible;
 }
 
 bool ChildProcessLauncherPriority::operator==(
@@ -195,6 +198,7 @@
   return visible == other.visible &&
          has_media_stream == other.has_media_stream &&
          has_foreground_service_worker == other.has_foreground_service_worker &&
+         has_only_low_priority_frames == other.has_only_low_priority_frames &&
          frame_depth == other.frame_depth &&
          intersects_viewport == other.intersects_viewport &&
          boost_for_pending_views == other.boost_for_pending_views
diff --git a/content/browser/child_process_launcher.h b/content/browser/child_process_launcher.h
index 0e5f225..0136b71 100644
--- a/content/browser/child_process_launcher.h
+++ b/content/browser/child_process_launcher.h
@@ -59,6 +59,7 @@
   ChildProcessLauncherPriority(bool visible,
                                bool has_media_stream,
                                bool has_foreground_service_worker,
+                               bool has_only_low_priority_frames,
                                unsigned int frame_depth,
                                bool intersects_viewport,
                                bool boost_for_pending_views
@@ -70,6 +71,7 @@
       : visible(visible),
         has_media_stream(has_media_stream),
         has_foreground_service_worker(has_foreground_service_worker),
+        has_only_low_priority_frames(has_only_low_priority_frames),
         frame_depth(frame_depth),
         intersects_viewport(intersects_viewport),
         boost_for_pending_views(boost_for_pending_views)
@@ -106,6 +108,10 @@
   // processes.
   bool has_foreground_service_worker;
 
+  // True if this ChildProcessLauncher has a non-zero number of frames attached
+  // to it and they're all low priority.
+  bool has_only_low_priority_frames;
+
   // |frame_depth| is the depth of the shallowest frame this process is
   // responsible for which has |visible| visibility. It only makes sense to
   // compare this property for two ChildProcessLauncherPriority instances with
diff --git a/content/browser/devtools/devtools_instrumentation.cc b/content/browser/devtools/devtools_instrumentation.cc
index 9eb2832..4ed8ea4 100644
--- a/content/browser/devtools/devtools_instrumentation.cc
+++ b/content/browser/devtools/devtools_instrumentation.cc
@@ -51,6 +51,22 @@
     DispatchToAgents(ftn, method, std::forward<Args>(args)...);
 }
 
+template <typename Handler, typename... MethodArgs, typename... Args>
+void DispatchToWorkerAgents(int32_t worker_process_id,
+                            int32_t worker_route_id,
+                            void (Handler::*method)(MethodArgs...),
+                            Args&&... args) {
+  ServiceWorkerDevToolsAgentHost* service_worker_host =
+      ServiceWorkerDevToolsManager::GetInstance()
+          ->GetDevToolsAgentHostForWorker(worker_process_id, worker_route_id);
+  if (!service_worker_host)
+    return;
+  for (auto* h : Handler::ForAgentHost(service_worker_host))
+    (h->*method)(std::forward<Args>(args)...);
+
+  // TODO(crbug.com/1004979): Look for shared worker hosts here as well.
+}
+
 FrameTreeNode* GetFtnForNetworkRequest(int process_id, int routing_id) {
   // Navigation requests start in the browser, before process_id is assigned, so
   // the id is set to 0. In these situations, the routing_id is the frame tree
@@ -451,11 +467,22 @@
     const net::CookieStatusList& request_cookie_list,
     const std::vector<network::mojom::HttpRawHeaderPairPtr>& request_headers) {
   FrameTreeNode* ftn = GetFtnForNetworkRequest(process_id, routing_id);
-  if (!ftn)
+  if (ftn) {
+    DispatchToAgents(ftn,
+                     &protocol::NetworkHandler::OnRequestWillBeSentExtraInfo,
+                     devtools_request_id, request_cookie_list, request_headers);
     return;
+  }
 
-  DispatchToAgents(ftn, &protocol::NetworkHandler::OnRequestWillBeSentExtraInfo,
-                   devtools_request_id, request_cookie_list, request_headers);
+  // In the case of service worker network requests, there is no
+  // FrameTreeNode to use so instead we use the "routing_id" created with the
+  // worker and sent to the renderer process to send as the render_frame_id in
+  // the renderer's network::ResourceRequest which gets plubmed to here as
+  // routing_id.
+  DispatchToWorkerAgents(
+      process_id, routing_id,
+      &protocol::NetworkHandler::OnRequestWillBeSentExtraInfo,
+      devtools_request_id, request_cookie_list, request_headers);
 }
 
 void OnResponseReceivedExtraInfo(
@@ -466,12 +493,19 @@
     const std::vector<network::mojom::HttpRawHeaderPairPtr>& response_headers,
     const base::Optional<std::string>& response_headers_text) {
   FrameTreeNode* ftn = GetFtnForNetworkRequest(process_id, routing_id);
-  if (!ftn)
+  if (ftn) {
+    DispatchToAgents(ftn,
+                     &protocol::NetworkHandler::OnResponseReceivedExtraInfo,
+                     devtools_request_id, response_cookie_list,
+                     response_headers, response_headers_text);
     return;
+  }
 
-  DispatchToAgents(ftn, &protocol::NetworkHandler::OnResponseReceivedExtraInfo,
-                   devtools_request_id, response_cookie_list, response_headers,
-                   response_headers_text);
+  // See comment on DispatchToWorkerAgents in OnRequestWillBeSentExtraInfo.
+  DispatchToWorkerAgents(process_id, routing_id,
+                         &protocol::NetworkHandler::OnResponseReceivedExtraInfo,
+                         devtools_request_id, response_cookie_list,
+                         response_headers, response_headers_text);
 }
 
 }  // namespace devtools_instrumentation
diff --git a/content/browser/download/download_manager_impl.cc b/content/browser/download/download_manager_impl.cc
index 17c3898a..eb4b7547 100644
--- a/content/browser/download/download_manager_impl.cc
+++ b/content/browser/download/download_manager_impl.cc
@@ -727,7 +727,7 @@
 void DownloadManagerImpl::ResumeInterruptedDownload(
     std::unique_ptr<download::DownloadUrlParameters> params,
     const GURL& site_url) {
-  BeginDownloadInternal(std::move(params), nullptr /* blob_data_handle */,
+  BeginDownloadInternal(std::move(params),
                         nullptr /* blob_url_loader_factory */, false, site_url);
 }
 
@@ -838,13 +838,11 @@
 
 void DownloadManagerImpl::DownloadUrl(
     std::unique_ptr<download::DownloadUrlParameters> params) {
-  DownloadUrl(std::move(params), nullptr /* blob_data_handle */,
-              nullptr /* blob_url_loader_factory */);
+  DownloadUrl(std::move(params), nullptr /* blob_url_loader_factory */);
 }
 
 void DownloadManagerImpl::DownloadUrl(
     std::unique_ptr<download::DownloadUrlParameters> params,
-    std::unique_ptr<storage::BlobDataHandle> blob_data_handle,
     scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory) {
   if (params->post_id() >= 0) {
     // Check this here so that the traceback is more useful.
@@ -858,8 +856,8 @@
                                       params->render_frame_host_routing_id());
   if (rfh)
     params->set_frame_tree_node_id(rfh->GetFrameTreeNodeId());
-  BeginDownloadInternal(std::move(params), std::move(blob_data_handle),
-                        std::move(blob_url_loader_factory), true,
+  BeginDownloadInternal(std::move(params), std::move(blob_url_loader_factory),
+                        true,
                         rfh ? rfh->GetSiteInstance()->GetSiteURL() : GURL());
 }
 
@@ -1285,7 +1283,6 @@
 
 void DownloadManagerImpl::BeginDownloadInternal(
     std::unique_ptr<download::DownloadUrlParameters> params,
-    std::unique_ptr<storage::BlobDataHandle> blob_data_handle,
     scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,
     bool is_new_download,
     const GURL& site_url) {
diff --git a/content/browser/download/download_manager_impl.h b/content/browser/download/download_manager_impl.h
index 63b66ecc..2448011b 100644
--- a/content/browser/download/download_manager_impl.h
+++ b/content/browser/download/download_manager_impl.h
@@ -88,7 +88,6 @@
   void DownloadUrl(
       std::unique_ptr<download::DownloadUrlParameters> parameters) override;
   void DownloadUrl(std::unique_ptr<download::DownloadUrlParameters> params,
-                   std::unique_ptr<storage::BlobDataHandle> blob_data_handle,
                    scoped_refptr<network::SharedURLLoaderFactory>
                        blob_url_loader_factory) override;
   void AddObserver(Observer* observer) override;
@@ -243,7 +242,6 @@
   // Helper method to start or resume a download.
   void BeginDownloadInternal(
       std::unique_ptr<download::DownloadUrlParameters> params,
-      std::unique_ptr<storage::BlobDataHandle> blob_data_handle,
       scoped_refptr<network::SharedURLLoaderFactory> blob_url_loader_factory,
       bool is_new_download,
       const GURL& site_url);
diff --git a/content/browser/download/download_manager_impl_unittest.cc b/content/browser/download/download_manager_impl_unittest.cc
index 637c7ca..cf1e3383 100644
--- a/content/browser/download/download_manager_impl_unittest.cc
+++ b/content/browser/download/download_manager_impl_unittest.cc
@@ -25,8 +25,10 @@
 #include "base/strings/string16.h"
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
+#include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
 #include "components/download/public/common/download_create_info.h"
+#include "components/download/public/common/download_features.h"
 #include "components/download/public/common/download_file_factory.h"
 #include "components/download/public/common/download_interrupt_reasons.h"
 #include "components/download/public/common/download_item.h"
@@ -67,6 +69,8 @@
 
 namespace {
 
+const char kGuid[] = "8DF158E8-C980-4618-BB03-EBA3242EB48B";
+
 bool URLAlwaysSafe(int render_process_id, const GURL& url) {
   return true;
 }
@@ -473,6 +477,27 @@
     return item;
   }
 
+  // Helper function to create a download item.
+  download::DownloadItem* CreateDownloadItem(
+      const base::Time& start_time,
+      const std::vector<GURL>& url_chain,
+      download::DownloadItem::DownloadState download_state) {
+    download::DownloadItem* download_item =
+        download_manager_->CreateDownloadItem(
+            kGuid, 10, base::FilePath(), base::FilePath(), url_chain,
+            GURL("http://example.com/a"), GURL("http://example.com/a"),
+            GURL("http://example.com/a"), GURL("http://example.com/a"),
+            url::Origin::Create(GURL("http://example.com/")),
+            "application/octet-stream", "application/octet-stream", start_time,
+            base::Time::Now(), std::string(), std::string(), 10, 10,
+            std::string(), download_state,
+            download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+            download::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED, false,
+            base::Time::Now(), true,
+            std::vector<download::DownloadItem::ReceivedSlice>());
+    return download_item;
+  }
+
   download::MockDownloadItemImpl& GetMockDownloadItem(int id) {
     download::MockDownloadItemImpl* itemp =
         mock_download_item_factory_->GetItem(id);
@@ -678,24 +703,12 @@
 
   ASSERT_FALSE(download_manager_->GetDownloadByGuid(""));
 
-  const char kGuid[] = "8DF158E8-C980-4618-BB03-EBA3242EB48B";
   std::vector<GURL> url_chain;
   url_chain.emplace_back("http://example.com/1.zip");
-  download::DownloadItem* persisted_item =
-      download_manager_->CreateDownloadItem(
-          kGuid, 10, base::FilePath(), base::FilePath(), url_chain,
-          GURL("http://example.com/a"), GURL("http://example.com/a"),
-          GURL("http://example.com/a"), GURL("http://example.com/a"),
-          url::Origin::Create(GURL("http://example.com/")),
-          "application/octet-stream", "application/octet-stream",
-          base::Time::Now(), base::Time::Now(), std::string(), std::string(),
-          10, 10, std::string(), download::DownloadItem::INTERRUPTED,
-          download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
-          download::DOWNLOAD_INTERRUPT_REASON_SERVER_FAILED, false,
-          base::Time::Now(), true,
-          std::vector<download::DownloadItem::ReceivedSlice>());
+  EXPECT_CALL(GetMockObserver(), OnDownloadCreated(download_manager_.get(), _));
+  download::DownloadItem* persisted_item = CreateDownloadItem(
+      base::Time::Now(), url_chain, download::DownloadItem::INTERRUPTED);
   ASSERT_TRUE(persisted_item);
-
   ASSERT_EQ(persisted_item, download_manager_->GetDownloadByGuid(kGuid));
 }
 
@@ -732,7 +745,6 @@
 // DownloadManager.
 TEST_F(DownloadManagerTest, OnInProgressDownloadsLoaded) {
   auto in_progress_manager = std::make_unique<TestInProgressManager>();
-  const char kGuid[] = "8DF158E8-C980-4618-BB03-EBA3242EB48B";
   std::vector<GURL> url_chain;
   url_chain.emplace_back("http://example.com/1.zip");
   auto in_progress_item = std::make_unique<download::DownloadItemImpl>(
@@ -770,4 +782,36 @@
   ASSERT_FALSE(download_manager_->GetDownloadByGuid(kGuid));
 }
 
+// Verifies that expired canceled or interrupted downloads are deleted
+// correctly.
+TEST_F(DownloadManagerTest, DeleteExpiredDownload) {
+  base::test::ScopedFeatureList scoped_feature_list;
+  std::map<std::string, std::string> params = {
+      {download::kExpiredDownloadDeleteTimeFinchKey, base::NumberToString(1)}};
+  scoped_feature_list.InitAndEnableFeatureWithParameters(
+      download::features::kDeleteExpiredDownloads, params);
+
+  std::vector<GURL> url_chain;
+  url_chain.emplace_back("http://example.com/1.zip");
+  auto expired_start_time = base::Time::Now() - base::TimeDelta::FromDays(10);
+  download::DownloadItem* download_item = CreateDownloadItem(
+      expired_start_time, url_chain, download::DownloadItem::INTERRUPTED);
+  EXPECT_FALSE(download_item)
+      << "Expired interrupted download will be deleted.";
+
+  download_item = CreateDownloadItem(expired_start_time, url_chain,
+                                     download::DownloadItem::CANCELLED);
+  EXPECT_FALSE(download_item) << "Expired canceled download will be deleted.";
+
+  download_item = CreateDownloadItem(expired_start_time, std::vector<GURL>(),
+                                     download::DownloadItem::COMPLETE);
+  EXPECT_FALSE(download_item) << "Download without URL chain will be deleted.";
+
+  EXPECT_CALL(GetMockObserver(), OnDownloadCreated(download_manager_.get(), _));
+  download_item = CreateDownloadItem(expired_start_time, url_chain,
+                                     download::DownloadItem::COMPLETE);
+  EXPECT_TRUE(download_item)
+      << "Expired complete download will not be deleted.";
+}
+
 }  // namespace content
diff --git a/content/browser/fileapi/file_system_url_loader_factory_browsertest.cc b/content/browser/fileapi/file_system_url_loader_factory_browsertest.cc
index c7eb48d..fda4523 100644
--- a/content/browser/fileapi/file_system_url_loader_factory_browsertest.cc
+++ b/content/browser/fileapi/file_system_url_loader_factory_browsertest.cc
@@ -664,10 +664,10 @@
   EXPECT_TRUE(client->has_received_completion());
   std::string response_text = ReadDataPipe(client->response_body_release());
   EXPECT_EQ(kTestFileData, response_text);
-  ASSERT_TRUE(client->response_head().headers) << "No response headers";
-  EXPECT_EQ(200, client->response_head().headers->response_code());
+  ASSERT_TRUE(client->response_head()->headers) << "No response headers";
+  EXPECT_EQ(200, client->response_head()->headers->response_code());
   std::string cache_control;
-  EXPECT_TRUE(client->response_head().headers->GetNormalizedHeader(
+  EXPECT_TRUE(client->response_head()->headers->GetNormalizedHeader(
       "cache-control", &cache_control));
   EXPECT_EQ("no-cache", cache_control);
 }
@@ -838,8 +838,8 @@
   EXPECT_TRUE(client->has_received_response());
   EXPECT_TRUE(client->has_received_completion());
 
-  EXPECT_EQ(mime_type_direct, client->response_head().mime_type);
-  EXPECT_TRUE(client->response_head().did_mime_sniff);
+  EXPECT_EQ(mime_type_direct, client->response_head()->mime_type);
+  EXPECT_TRUE(client->response_head()->did_mime_sniff);
 }
 
 IN_PROC_BROWSER_TEST_P(FileSystemURLLoaderFactoryTest, FileIncognito) {
@@ -865,7 +865,7 @@
   EXPECT_TRUE(client->has_received_completion());
   std::string response_text = ReadDataPipe(client->response_body_release());
   EXPECT_EQ(kTestFileData, response_text);
-  EXPECT_EQ(200, client->response_head().headers->response_code());
+  EXPECT_EQ(200, client->response_head()->headers->response_code());
 }
 
 IN_PROC_BROWSER_TEST_P(FileSystemURLLoaderFactoryTest, FileAutoMountFileTest) {
@@ -878,10 +878,10 @@
   EXPECT_TRUE(client->has_received_completion());
   std::string response_text = ReadDataPipe(client->response_body_release());
   EXPECT_EQ(kTestFileData, response_text);
-  EXPECT_EQ(200, client->response_head().headers->response_code());
+  EXPECT_EQ(200, client->response_head()->headers->response_code());
 
   std::string cache_control;
-  EXPECT_TRUE(client->response_head().headers->GetNormalizedHeader(
+  EXPECT_TRUE(client->response_head()->headers->GetNormalizedHeader(
       "cache-control", &cache_control));
   EXPECT_EQ("no-cache", cache_control);
 
diff --git a/content/browser/frame_host/render_frame_host_delegate.cc b/content/browser/frame_host/render_frame_host_delegate.cc
index e4f2dcf..4dfe0da 100644
--- a/content/browser/frame_host/render_frame_host_delegate.cc
+++ b/content/browser/frame_host/render_frame_host_delegate.cc
@@ -163,4 +163,9 @@
   return nullptr;
 }
 
+bool RenderFrameHostDelegate::IsFrameLowPriority(
+    const RenderFrameHost* render_frame_host) {
+  return false;
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/render_frame_host_delegate.h b/content/browser/frame_host/render_frame_host_delegate.h
index 7ab07c2..43ce596 100644
--- a/content/browser/frame_host/render_frame_host_delegate.h
+++ b/content/browser/frame_host/render_frame_host_delegate.h
@@ -455,6 +455,9 @@
   virtual RenderFrameHostImpl* GetMainFrameForInnerDelegate(
       FrameTreeNode* frame_tree_node);
 
+  // Determine if the frame is of a low priority.
+  virtual bool IsFrameLowPriority(const RenderFrameHost* render_frame_host);
+
  protected:
   virtual ~RenderFrameHostDelegate() {}
 };
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index d85525b..1b8c55f 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -969,6 +969,10 @@
   ClearAllWebUI();
 
   SetLastCommittedSiteUrl(GURL());
+  RenderProcessHostImpl* rph =
+      static_cast<RenderProcessHostImpl*>(GetProcess());
+  rph->UpdateFrameWithPriority(last_committed_document_priority_,
+                               base::nullopt);
 
   if (overlay_routing_token_)
     g_token_frame_map.Get().erase(*overlay_routing_token_);
@@ -2298,6 +2302,18 @@
   last_committed_url_ = url;
 }
 
+void RenderFrameHostImpl::UpdateRenderProcessHostFramePriorities() {
+  const auto new_committed_document_priority =
+      (delegate_ && delegate_->IsFrameLowPriority(this))
+          ? RenderProcessHostImpl::FramePriority::kLow
+          : RenderProcessHostImpl::FramePriority::kNormal;
+  RenderProcessHostImpl* rph =
+      static_cast<RenderProcessHostImpl*>(GetProcess());
+  rph->UpdateFrameWithPriority(last_committed_document_priority_,
+                               new_committed_document_priority);
+  last_committed_document_priority_ = new_committed_document_priority;
+}
+
 void RenderFrameHostImpl::OnDetach() {
   if (!parent_) {
     bad_message::ReceivedBadMessage(GetProcess(),
@@ -6900,6 +6916,8 @@
 
   last_http_status_code_ = validated_params->http_status_code;
   UpdateSiteURL(validated_params->url, validated_params->url_is_unreachable);
+  if (!is_same_document_navigation)
+    UpdateRenderProcessHostFramePriorities();
 
   // Set the state whether this navigation is to an MHTML document, since there
   // are certain security checks that we cannot apply to subframes in MHTML
@@ -7650,4 +7668,16 @@
   }
 }
 
+void RenderFrameHostImpl::EnableMojoJsBindings() {
+  // This method should only be called on RenderFrameHost which is for a WebUI.
+  DCHECK_NE(WebUI::kNoWebUI,
+            WebUIControllerFactoryRegistry::GetInstance()->GetWebUIType(
+                GetSiteInstance()->GetBrowserContext(),
+                site_instance_->GetSiteURL()));
+
+  if (!frame_bindings_control_)
+    GetRemoteAssociatedInterfaces()->GetInterface(&frame_bindings_control_);
+  frame_bindings_control_->EnableMojoJsBindings();
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/render_frame_host_impl.h b/content/browser/frame_host/render_frame_host_impl.h
index 91251c4..1584b6d 100644
--- a/content/browser/frame_host/render_frame_host_impl.h
+++ b/content/browser/frame_host/render_frame_host_impl.h
@@ -486,6 +486,13 @@
     return should_reuse_web_ui_ ? web_ui_.get() : pending_web_ui_.get();
   }
 
+  // Enable Mojo JavaScript bindings in the renderer process. It will be
+  // effective on the first creation of script context after the call is made.
+  // If called at frame creation time (RenderFrameCreated) or just before a
+  // document is committed (ReadyToCommitNavigation), the resulting document
+  // will have the JS bindings enabled.
+  void EnableMojoJsBindings();
+
   // Returns this RenderFrameHost's loading state. This method is only used by
   // FrameTreeNode. The proper way to check whether a frame is loading is to
   // call FrameTreeNode::IsLoading.
@@ -1293,6 +1300,9 @@
 
   class DroppedInterfaceRequestLogger;
 
+  // Update the RenderProcessHost priority when a navigation occurs.
+  void UpdateRenderProcessHostFramePriorities();
+
   // IPC Message handlers.
   void OnDetach();
   void OnOpenURL(const FrameHostMsg_OpenURL_Params& params);
@@ -1929,6 +1939,11 @@
   // Track this frame's last committed URL.
   GURL last_committed_url_;
 
+  // Track the frame priority of the last committed document, which is nullopt
+  // prior to the first commit.
+  base::Optional<RenderProcessHostImpl::FramePriority>
+      last_committed_document_priority_;
+
   // Track this frame's last committed origin.
   url::Origin last_committed_origin_;
 
diff --git a/content/browser/frame_host/render_frame_message_filter.cc b/content/browser/frame_host/render_frame_message_filter.cc
index 1202e49..920f1983 100644
--- a/content/browser/frame_host/render_frame_message_filter.cc
+++ b/content/browser/frame_host/render_frame_message_filter.cc
@@ -107,12 +107,8 @@
   }
 }
 
-// |blob_data_handle| is only here for the legacy code path. With network
-// service enabled |blob_url_token| should be provided and will be used instead
-// to download the correct blob.
 void DownloadUrlOnUIThread(
     std::unique_ptr<download::DownloadUrlParameters> parameters,
-    std::unique_ptr<storage::BlobDataHandle> blob_data_handle,
     mojo::PendingRemote<blink::mojom::BlobURLToken> blob_url_token) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
@@ -134,7 +130,6 @@
       BrowserContext::GetDownloadManager(browser_context);
   parameters->set_download_source(download::DownloadSource::FROM_RENDERER);
   download_manager->DownloadUrl(std::move(parameters),
-                                std::move(blob_data_handle),
                                 std::move(blob_url_loader_factory));
 }
 
@@ -360,24 +355,9 @@
       Referrer::ReferrerPolicyForUrlRequest(referrer.policy));
   parameters->set_initiator(initiator);
 
-  // If network service is enabled we should always have a |blob_url_token|,
-  // which will be used to download the correct blob. But in the legacy
-  // non-network service code path we still need to look up the BlobDataHandle
-  // for the URL here, to make sure the correct blob ends up getting downloaded.
-  std::unique_ptr<storage::BlobDataHandle> blob_data_handle;
-  if (url.SchemeIsBlob()) {
-    ChromeBlobStorageContext* blob_context =
-        GetChromeBlobStorageContextForResourceContext(resource_context_);
-
-    blob_data_handle = blob_context->context()->GetBlobDataFromPublicURL(url);
-    // Don't care if the above fails. We are going to let the download go
-    // through and allow it to be interrupted so that the embedder can deal.
-  }
-
-  base::PostTask(
-      FROM_HERE, {BrowserThread::UI},
-      base::BindOnce(&DownloadUrlOnUIThread, std::move(parameters),
-                     std::move(blob_data_handle), std::move(blob_url_token)));
+  base::PostTask(FROM_HERE, {BrowserThread::UI},
+                 base::BindOnce(&DownloadUrlOnUIThread, std::move(parameters),
+                                std::move(blob_url_token)));
 }
 
 void RenderFrameMessageFilter::OnCreateChildFrame(
diff --git a/content/browser/loader/cross_site_document_blocking_browsertest.cc b/content/browser/loader/cross_site_document_blocking_browsertest.cc
index e30ad2e..e46dbf3 100644
--- a/content/browser/loader/cross_site_document_blocking_browsertest.cc
+++ b/content/browser/loader/cross_site_document_blocking_browsertest.cc
@@ -198,7 +198,7 @@
 
   ~RequestInterceptor() {
     WaitForCleanUpOnInterceptorThread(
-        network::ResourceResponseHead(), "",
+        network::mojom::URLResponseHead::New(), "",
         network::URLLoaderCompletionStatus(net::ERR_NOT_IMPLEMENTED));
   }
 
@@ -216,8 +216,8 @@
     }
 
     // Wait until IO cleanup completes.
-    WaitForCleanUpOnInterceptorThread(test_client_.response_head(), body_,
-                                      test_client_.completion_status());
+    WaitForCleanUpOnInterceptorThread(test_client_.response_head().Clone(),
+                                      body_, test_client_.completion_status());
 
     // Mark the request as completed (for DCHECK purposes).
     request_completed_ = true;
@@ -229,7 +229,7 @@
     return test_client_.completion_status();
   }
 
-  const network::ResourceResponseHead& response_head() const {
+  const network::mojom::URLResponseHeadPtr& response_head() const {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
     DCHECK(request_completed_);
     return test_client_.response_head();
@@ -251,8 +251,8 @@
       EXPECT_EQ(0, completion_status().decoded_body_length);
 
       // Verify that other response parts have been sanitized.
-      EXPECT_EQ(0u, response_head().content_length);
-      const std::string& headers = response_head().headers->raw_headers();
+      EXPECT_EQ(0u, response_head()->content_length);
+      const std::string& headers = response_head()->headers->raw_headers();
       EXPECT_THAT(headers, Not(HasSubstr("Content-Length")));
       EXPECT_THAT(headers, Not(HasSubstr("Content-Type")));
 
@@ -345,7 +345,7 @@
   }
 
   void WaitForCleanUpOnInterceptorThread(
-      network::ResourceResponseHead response_head,
+      network::mojom::URLResponseHeadPtr response_head,
       std::string response_body,
       network::URLLoaderCompletionStatus status) {
     DCHECK_CURRENTLY_ON(BrowserThread::UI);
@@ -358,8 +358,8 @@
       interceptor_task_runner_->PostTaskAndReply(
           FROM_HERE,
           base::BindOnce(&RequestInterceptor::CleanUpOnInterceptorThread,
-                         base::Unretained(this), response_head, response_body,
-                         status),
+                         base::Unretained(this), std::move(response_head),
+                         response_body, status),
           run_loop.QuitClosure());
       run_loop.Run();
     }
@@ -367,16 +367,17 @@
     cleanup_done_ = true;
   }
 
-  void CleanUpOnInterceptorThread(network::ResourceResponseHead response_head,
-                                  std::string response_body,
-                                  network::URLLoaderCompletionStatus status) {
+  void CleanUpOnInterceptorThread(
+      network::mojom::URLResponseHeadPtr response_head,
+      std::string response_body,
+      network::URLLoaderCompletionStatus status) {
     if (!request_intercepted_)
       return;
 
     // Tell the |original_client_| that the request has completed (and that it
     // can release its URLLoaderClient.
     if (status.error_code == net::OK) {
-      original_client_->OnReceiveResponse(response_head);
+      original_client_->OnReceiveResponse(std::move(response_head));
 
       mojo::DataPipe empty_data_pipe(response_body.size() + 1);
       original_client_->OnStartLoadingResponseBody(
@@ -859,7 +860,7 @@
 
   // Verify that most response headers have been removed by CORB.
   const std::string& headers =
-      interceptor.response_head().headers->raw_headers();
+      interceptor.response_head()->headers->raw_headers();
   EXPECT_THAT(headers, HasSubstr("Access-Control-Allow-Origin: https://other"));
   EXPECT_THAT(headers, Not(HasSubstr("Cache-Control")));
   EXPECT_THAT(headers, Not(HasSubstr("Content-Language")));
@@ -878,7 +879,7 @@
   EXPECT_EQ(0, interceptor.completion_status().decoded_body_length);
 
   // Verify that other response parts have been sanitized.
-  EXPECT_EQ(0u, interceptor.response_head().content_length);
+  EXPECT_EQ(0u, interceptor.response_head()->content_length);
 }
 
 // TODO(lukasza): https://crbug.com/154571: Enable this test on Android once
diff --git a/content/browser/locks/lock_manager.cc b/content/browser/locks/lock_manager.cc
index d51862d..eb76f03 100644
--- a/content/browser/locks/lock_manager.cc
+++ b/content/browser/locks/lock_manager.cc
@@ -74,12 +74,13 @@
   Lock(const std::string& name,
        LockMode mode,
        int64_t lock_id,
-       const std::string& client_id,
+       const ReceiverState& receiver_state,
        mojo::AssociatedRemote<blink::mojom::LockRequest> request)
       : name_(name),
         mode_(mode),
-        client_id_(client_id),
         lock_id_(lock_id),
+        client_id_(receiver_state.client_id),
+        execution_context_(receiver_state.execution_context),
         request_(std::move(request)) {}
 
   ~Lock() = default;
@@ -125,13 +126,17 @@
   LockMode mode() const { return mode_; }
   int64_t lock_id() const { return lock_id_; }
   const std::string& client_id() const { return client_id_; }
+  const ExecutionContext& execution_context() const {
+    return execution_context_;
+  }
   bool is_granted() const { return !!handle_; }
 
  private:
   const std::string name_;
   const LockMode mode_;
-  const std::string client_id_;
   const int64_t lock_id_;
+  const std::string client_id_;
+  const ExecutionContext execution_context_;
 
   // Exactly one of the following is non-null at any given time.
 
@@ -170,28 +175,27 @@
   void PreemptLock(int64_t lock_id,
                    const std::string& name,
                    LockMode mode,
-                   const std::string& client_id,
                    mojo::AssociatedRemote<blink::mojom::LockRequest> request,
-                   const url::Origin origin) {
+                   const ReceiverState& receiver_state) {
     // Preempting shared locks is not supported.
     DCHECK_EQ(mode, LockMode::EXCLUSIVE);
     std::list<Lock>& request_queue = resource_names_to_requests_[name];
     while (!request_queue.empty() && request_queue.front().is_granted())
       BreakFront(request_queue);
-    request_queue.emplace_front(name, mode, lock_id, client_id,
+    request_queue.emplace_front(name, mode, lock_id, receiver_state,
                                 std::move(request));
     auto it = request_queue.begin();
     lock_id_to_iterator_.emplace(it->lock_id(), it);
-    it->Grant(lock_manager_->weak_ptr_factory_.GetWeakPtr(), origin);
+    it->Grant(lock_manager_->weak_ptr_factory_.GetWeakPtr(),
+              receiver_state.origin);
   }
 
   void AddRequest(int64_t lock_id,
                   const std::string& name,
                   LockMode mode,
-                  const std::string& client_id,
                   mojo::AssociatedRemote<blink::mojom::LockRequest> request,
                   WaitMode wait,
-                  const url::Origin origin) {
+                  const ReceiverState& receiver_state) {
     DCHECK(wait != WaitMode::PREEMPT);
     std::list<Lock>& request_queue = resource_names_to_requests_[name];
     bool can_grant = request_queue.empty() ||
@@ -204,12 +208,14 @@
       return;
     }
 
-    request_queue.emplace_back(name, mode, lock_id, client_id,
+    request_queue.emplace_back(name, mode, lock_id, receiver_state,
                                std::move(request));
     auto it = --(request_queue.end());
     lock_id_to_iterator_.emplace(it->lock_id(), it);
-    if (can_grant)
-      it->Grant(lock_manager_->weak_ptr_factory_.GetWeakPtr(), origin);
+    if (can_grant) {
+      it->Grant(lock_manager_->weak_ptr_factory_.GetWeakPtr(),
+                receiver_state.origin);
+    }
   }
 
   void EraseLock(int64_t lock_id, const url::Origin& origin) {
@@ -319,7 +325,7 @@
   const std::string client_id = base::GenerateGUID();
 
   receivers_.Add(this, std::move(receiver),
-                 {client_id, render_process_id, render_frame_id, origin});
+                 {client_id, {render_process_id, render_frame_id}, origin});
 }
 
 void LockManager::RequestLock(
@@ -354,11 +360,10 @@
 
   OriginState& origin_state = origins_.find(context.origin)->second;
   if (wait == WaitMode::PREEMPT) {
-    origin_state.PreemptLock(lock_id, name, mode, context.client_id,
-                             std::move(request), context.origin);
+    origin_state.PreemptLock(lock_id, name, mode, std::move(request), context);
   } else
-    origin_state.AddRequest(lock_id, name, mode, context.client_id,
-                            std::move(request), wait, context.origin);
+    origin_state.AddRequest(lock_id, name, mode, std::move(request), wait,
+                            context);
 }
 
 void LockManager::ReleaseLock(const url::Origin& origin, int64_t lock_id) {
diff --git a/content/browser/locks/lock_manager.h b/content/browser/locks/lock_manager.h
index 25ed9c95..b16f1f99 100644
--- a/content/browser/locks/lock_manager.h
+++ b/content/browser/locks/lock_manager.h
@@ -59,16 +59,22 @@
   // State for a particular origin.
   class OriginState;
 
+  // Describes a frame or a worker.
+  struct ExecutionContext {
+    // The identifier of the process hosting this frame or worker.
+    int render_process_id;
+
+    // The frame identifier, or MSG_ROUTING_NONE if this describes a worker
+    // (this means that dedicated/shared/service workers are not distinguished).
+    int render_frame_id;
+  };
+
   // State for each client held in |receivers_|.
   struct ReceiverState {
     std::string client_id;
 
-    // Process owning this receiver.
-    int render_process_id;
-
-    // Frame owning this receiver. MSG_ROUTING_NONE if the receiver is owned by
-    // a worker.
-    int render_frame_id;
+    // ExecutionContext owning this receiver.
+    ExecutionContext execution_context;
 
     // Origin of the frame or worker owning this receiver.
     url::Origin origin;
diff --git a/content/browser/process_internals/process_internals_browsertest.cc b/content/browser/process_internals/process_internals_browsertest.cc
new file mode 100644
index 0000000..0febc13
--- /dev/null
+++ b/content/browser/process_internals/process_internals_browsertest.cc
@@ -0,0 +1,36 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/browser/child_process_security_policy_impl.h"
+#include "content/browser/renderer_host/render_process_host_impl.h"
+#include "content/public/test/browser_test_utils.h"
+#include "content/public/test/content_browser_test.h"
+#include "content/public/test/content_browser_test_utils.h"
+#include "content/shell/browser/shell.h"
+
+namespace content {
+
+class ProcessInternalsWebUiBrowserTest : public ContentBrowserTest {};
+
+// This test verifies that loading of the process-internals WebUI works
+// correctly and the process rendering it has no WebUI bindings.
+IN_PROC_BROWSER_TEST_F(ProcessInternalsWebUiBrowserTest, NoProcessBindings) {
+  GURL url("chrome://process-internals/#web-contents");
+  EXPECT_TRUE(NavigateToURL(shell(), url));
+
+  EXPECT_FALSE(ChildProcessSecurityPolicyImpl::GetInstance()->HasWebUIBindings(
+      shell()->web_contents()->GetMainFrame()->GetProcess()->GetID()));
+
+  // Execute script to ensure the page has loaded correctly and was successful
+  // at retrieving data from the browser process.
+  // Note: This requires using an isolated world in which to execute the
+  // script because WebUI has a default CSP policy denying "eval()", which is
+  // what EvalJs uses under the hood.
+  EXPECT_NE(-1,
+            EvalJs(shell()->web_contents()->GetMainFrame(),
+                   "document.body.innerHTML.search('Process Model Internals');",
+                   EXECUTE_SCRIPT_DEFAULT_OPTIONS, 1 /* world_id */));
+}
+
+}  // namespace content
diff --git a/content/browser/process_internals/process_internals_ui.cc b/content/browser/process_internals/process_internals_ui.cc
index c157b59c..3c7cb28 100644
--- a/content/browser/process_internals/process_internals_ui.cc
+++ b/content/browser/process_internals/process_internals_ui.cc
@@ -10,6 +10,7 @@
 
 #include "base/bind.h"
 #include "base/macros.h"
+#include "content/browser/frame_host/render_frame_host_impl.h"
 #include "content/browser/process_internals/process_internals.mojom.h"
 #include "content/browser/process_internals/process_internals_handler_impl.h"
 #include "content/grit/content_resources.h"
@@ -27,9 +28,9 @@
 
 ProcessInternalsUI::ProcessInternalsUI(WebUI* web_ui)
     : WebUIController(web_ui), WebContentsObserver(web_ui->GetWebContents()) {
-  // Grant only Mojo WebUI bindings, since this WebUI will not use
-  // chrome.send().
-  web_ui->SetBindings(content::BINDINGS_POLICY_MOJO_WEB_UI);
+  // This WebUI does not require any process bindings, so disable it early in
+  // initialization time.
+  web_ui->SetBindings(0);
 
   // Create a WebUIDataSource to serve the HTML/JS files to the WebUI.
   WebUIDataSource* source =
@@ -50,6 +51,12 @@
 
 ProcessInternalsUI::~ProcessInternalsUI() = default;
 
+void ProcessInternalsUI::RenderFrameCreated(RenderFrameHost* rfh) {
+  // Enable the JavaScript Mojo bindings in the renderer process, so the JS
+  // code can call the Mojo APIs exposed by this WebUI.
+  static_cast<RenderFrameHostImpl*>(rfh)->EnableMojoJsBindings();
+}
+
 void ProcessInternalsUI::BindProcessInternalsHandler(
     mojo::PendingReceiver<::mojom::ProcessInternalsHandler> receiver,
     RenderFrameHost* render_frame_host) {
diff --git a/content/browser/process_internals/process_internals_ui.h b/content/browser/process_internals/process_internals_ui.h
index a93cc751..2af1653 100644
--- a/content/browser/process_internals/process_internals_ui.h
+++ b/content/browser/process_internals/process_internals_ui.h
@@ -10,6 +10,7 @@
 #include <utility>
 
 #include "content/browser/process_internals/process_internals.mojom.h"
+#include "content/common/frame.mojom.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/browser/web_ui_controller.h"
 #include "mojo/public/cpp/bindings/pending_receiver.h"
@@ -32,6 +33,7 @@
       content::RenderFrameHost* render_frame_host,
       const std::string& interface_name,
       mojo::ScopedMessagePipeHandle* interface_pipe) override;
+  void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
 
   template <typename Binder>
   void AddHandlerToRegistry(Binder binder) {
diff --git a/content/browser/renderer_host/render_process_host_browsertest.cc b/content/browser/renderer_host/render_process_host_browsertest.cc
index 446db60..06a2cde 100644
--- a/content/browser/renderer_host/render_process_host_browsertest.cc
+++ b/content/browser/renderer_host/render_process_host_browsertest.cc
@@ -21,6 +21,7 @@
 #include "content/public/browser/render_process_host_observer.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_contents_observer.h"
+#include "content/public/common/content_features.h"
 #include "content/public/common/content_switches.h"
 #include "content/public/common/url_constants.h"
 #include "content/public/test/browser_test_utils.h"
@@ -49,7 +50,6 @@
 #endif
 
 namespace content {
-namespace {
 
 std::unique_ptr<net::test_server::HttpResponse> HandleBeacon(
     const net::test_server::HttpRequest& request) {
@@ -68,7 +68,19 @@
 class RenderProcessHostTest : public ContentBrowserTest,
                               public RenderProcessHostObserver {
  public:
-  RenderProcessHostTest() : process_exits_(0), host_destructions_(0) {}
+  RenderProcessHostTest()
+      : process_exits_(0), host_destructions_(0), use_frame_priority_(false) {}
+
+  void SetUp() override {
+    if (use_frame_priority_) {
+      feature_list_.InitAndEnableFeature(
+          features::kUseFramePriorityInRenderProcessHost);
+    } else {
+      feature_list_.InitAndDisableFeature(
+          features::kUseFramePriorityInRenderProcessHost);
+    }
+    ContentBrowserTest::SetUp();
+  }
 
   void SetUpCommandLine(base::CommandLine* command_line) override {
     command_line->AppendSwitchASCII(
@@ -81,6 +93,11 @@
     host_resolver()->AddRule("*", "127.0.0.1");
   }
 
+  void SetVisibleClients(RenderProcessHost* process, int32_t visible_clients) {
+    RenderProcessHostImpl* impl = static_cast<RenderProcessHostImpl*>(process);
+    impl->visible_clients_ = visible_clients;
+  }
+
  protected:
   void set_process_exit_callback(const base::Closure& callback) {
     process_exit_callback_ = callback;
@@ -104,6 +121,8 @@
   int process_exits_;
   int host_destructions_;
   base::Closure process_exit_callback_;
+  bool use_frame_priority_;
+  base::test::ScopedFeatureList feature_list_;
 };
 
 // A mock ContentBrowserClient that only considers a spare renderer to be a
@@ -1060,6 +1079,28 @@
     rph->RemoveObserver(this);
 }
 
+IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, LowPriorityFramesDisabled) {
+  // RenderProcessHostImpl::UpdateProcessPriority has an early check of
+  // run_renderer_in_process and exits for RenderProcessHosts without a child
+  // process launcher.  In order to skip initializing that here and the layer of
+  // indirection, we explicitly run in-process, which we must also disable once
+  // the test has finished to prevent crashing on exit.
+  RenderProcessHost::SetRunRendererInProcess(true);
+  RenderProcessHostImpl* process = static_cast<RenderProcessHostImpl*>(
+      RenderProcessHostImpl::CreateRenderProcessHost(
+          ShellContentBrowserClient::Get()->browser_context(), nullptr, nullptr,
+          false /* is_for_guests_only */));
+  // It starts off as normal priority.
+  EXPECT_FALSE(process->IsProcessBackgrounded());
+  // With the feature off it stays low priority when adding low priority frames.
+  process->UpdateFrameWithPriority(base::nullopt,
+                                   RenderProcessHostImpl::FramePriority::kLow);
+  process->UpdateFrameWithPriority(base::nullopt,
+                                   RenderProcessHostImpl::FramePriority::kLow);
+  EXPECT_FALSE(process->IsProcessBackgrounded());
+  RenderProcessHost::SetRunRendererInProcess(false);
+}
+
 // This test verifies properties of RenderProcessHostImpl *before* Init method
 // is called.
 IN_PROC_BROWSER_TEST_F(RenderProcessHostTest, ConstructedButNotInitializedYet) {
@@ -1102,5 +1143,73 @@
   process->Cleanup();
 }
 
-}  // namespace
+class RenderProcessHostFramePriorityTest : public RenderProcessHostTest {
+ public:
+  RenderProcessHostFramePriorityTest() : RenderProcessHostTest() {
+    use_frame_priority_ = true;
+  }
+};
+
+IN_PROC_BROWSER_TEST_F(RenderProcessHostFramePriorityTest,
+                       LowPriorityFramesEnabled) {
+  // RenderProcessHostImpl::UpdateProcessPriority has an early check of
+  // run_renderer_in_process and exits for RenderProcessHosts without a child
+  // process launcher.  In order to skip initializing that here and the layer of
+  // indirection, we explicitly run in-process, which we must also disable once
+  // the test has finished to prevent crashing on exit.
+  RenderProcessHost::SetRunRendererInProcess(true);
+  RenderProcessHostImpl* process = static_cast<RenderProcessHostImpl*>(
+      RenderProcessHostImpl::CreateRenderProcessHost(
+          ShellContentBrowserClient::Get()->browser_context(), nullptr, nullptr,
+          false /* is_for_guests_only */));
+  // For these tests, assume something is always visible.
+  SetVisibleClients(process, 1);
+  // When no frames are attached, it's not low priority.
+  EXPECT_FALSE(process->IsProcessBackgrounded());
+  // When all frames added are low priority, it's low priority.
+  process->UpdateFrameWithPriority(base::nullopt,
+                                   RenderProcessHostImpl::FramePriority::kLow);
+  process->UpdateFrameWithPriority(base::nullopt,
+                                   RenderProcessHostImpl::FramePriority::kLow);
+  EXPECT_TRUE(process->IsProcessBackgrounded());
+  // When all the low priority frames are removed, it's not low priority.
+  process->UpdateFrameWithPriority(RenderProcessHostImpl::FramePriority::kLow,
+                                   base::nullopt);
+  process->UpdateFrameWithPriority(RenderProcessHostImpl::FramePriority::kLow,
+                                   base::nullopt);
+  EXPECT_FALSE(process->IsProcessBackgrounded());
+  // When a low priority frame is added back in, it's low priority.
+  process->UpdateFrameWithPriority(base::nullopt,
+                                   RenderProcessHostImpl::FramePriority::kLow);
+  EXPECT_TRUE(process->IsProcessBackgrounded());
+  // As soon as a non-low priority frame is added, it's not low priority.
+  process->UpdateFrameWithPriority(
+      base::nullopt, RenderProcessHostImpl::FramePriority::kNormal);
+  EXPECT_FALSE(process->IsProcessBackgrounded());
+  // It remains not low priority even if we add more low priority frames.
+  process->UpdateFrameWithPriority(base::nullopt,
+                                   RenderProcessHostImpl::FramePriority::kLow);
+  EXPECT_FALSE(process->IsProcessBackgrounded());
+  // As soon as the non-low priority frame is removed, it becomes low priority.
+  process->UpdateFrameWithPriority(
+      RenderProcessHostImpl::FramePriority::kNormal, base::nullopt);
+  EXPECT_TRUE(process->IsProcessBackgrounded());
+  // Add a non-low priority frame, but then transition it to low, the process
+  // should go from unbackgrounded to backgrounded.
+  process->UpdateFrameWithPriority(
+      base::nullopt, RenderProcessHostImpl::FramePriority::kNormal);
+  EXPECT_FALSE(process->IsProcessBackgrounded());
+  process->UpdateFrameWithPriority(
+      RenderProcessHostImpl::FramePriority::kNormal,
+      RenderProcessHostImpl::FramePriority::kLow);
+  EXPECT_TRUE(process->IsProcessBackgrounded());
+  // Transition the frame back to normal priority, it becomes normal priority.
+  process->UpdateFrameWithPriority(
+      RenderProcessHostImpl::FramePriority::kLow,
+      RenderProcessHostImpl::FramePriority::kNormal);
+  EXPECT_FALSE(process->IsProcessBackgrounded());
+
+  RenderProcessHost::SetRunRendererInProcess(false);
+}
+
 }  // namespace content
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc
index 23ebf96..5a67b09 100644
--- a/content/browser/renderer_host/render_process_host_impl.cc
+++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -1465,6 +1465,7 @@
       priority_(!blink::kLaunchingProcessIsBackgrounded,
                 false /* has_media_stream */,
                 false /* has_foreground_service_worker */,
+                false /* all_low_priority_frames */,
                 frame_depth_,
                 false /* intersects_viewport */,
                 true /* boost_for_pending_views */
@@ -1744,6 +1745,10 @@
     InitializeChannelProxy();
 }
 
+bool RenderProcessHostImpl::HasOnlyLowPriorityFrames() {
+  return (low_priority_frames_ > 0) && (total_frames_ == low_priority_frames_);
+}
+
 void RenderProcessHostImpl::InitializeChannelProxy() {
   scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
       base::CreateSingleThreadTaskRunner({BrowserThread::IO});
@@ -2659,6 +2664,25 @@
   UpdateProcessPriorityInputs();
 }
 
+void RenderProcessHostImpl::UpdateFrameWithPriority(
+    base::Optional<FramePriority> previous_priority,
+    base::Optional<FramePriority> new_priority) {
+  if (!base::FeatureList::IsEnabled(
+          features::kUseFramePriorityInRenderProcessHost)) {
+    return;
+  }
+
+  const bool previous_all_low_priority_frames = HasOnlyLowPriorityFrames();
+  total_frames_ =
+      total_frames_ - (previous_priority ? 1 : 0) + (new_priority ? 1 : 0);
+  low_priority_frames_ =
+      low_priority_frames_ -
+      (previous_priority && previous_priority == FramePriority::kLow ? 1 : 0) +
+      (new_priority && new_priority == FramePriority::kLow ? 1 : 0);
+  if (previous_all_low_priority_frames != HasOnlyLowPriorityFrames())
+    UpdateProcessPriority();
+}
+
 int RenderProcessHostImpl::VisibleClientCount() {
   return visible_clients_;
 }
@@ -4382,7 +4406,7 @@
       visible_clients_ > 0 || base::CommandLine::ForCurrentProcess()->HasSwitch(
                                   switches::kDisableRendererBackgrounding),
       media_stream_count_ > 0, foreground_service_worker_count_ > 0,
-      frame_depth_, intersects_viewport_,
+      HasOnlyLowPriorityFrames(), frame_depth_, intersects_viewport_,
       !!pending_views_ /* boost_for_pending_views */
 #if defined(OS_ANDROID)
       ,
@@ -4390,11 +4414,11 @@
 #endif
   );
 
+  if (priority_ == priority)
+    return;
   const bool background_state_changed =
       priority_.is_background() != priority.is_background();
   const bool visibility_state_changed = priority_.visible != priority.visible;
-  if (priority_ == priority)
-    return;
 
   TRACE_EVENT2("renderer_host", "RenderProcessHostImpl::UpdateProcessPriority",
                "should_background", priority.is_background(),
@@ -4439,14 +4463,14 @@
 }
 
 void RenderProcessHostImpl::SendProcessStateToRenderer() {
-  mojom::RenderProcessState process_state;
-  if (priority_.is_background())
-    process_state = mojom::RenderProcessState::kBackgrounded;
-  else if (priority_.visible)
-    process_state = mojom::RenderProcessState::kVisible;
-  else
-    process_state = mojom::RenderProcessState::kHidden;
-  GetRendererInterface()->SetProcessState(process_state);
+  mojom::RenderProcessBackgroundState background_state =
+      priority_.is_background()
+          ? mojom::RenderProcessBackgroundState::kBackgrounded
+          : mojom::RenderProcessBackgroundState::kForegrounded;
+  mojom::RenderProcessVisibleState visible_state =
+      priority_.visible ? mojom::RenderProcessVisibleState::kVisible
+                        : mojom::RenderProcessVisibleState::kHidden;
+  GetRendererInterface()->SetProcessState(background_state, visible_state);
 }
 
 void RenderProcessHostImpl::OnProcessLaunched() {
diff --git a/content/browser/renderer_host/render_process_host_impl.h b/content/browser/renderer_host/render_process_host_impl.h
index a826a1e..1613e1ee 100644
--- a/content/browser/renderer_host/render_process_host_impl.h
+++ b/content/browser/renderer_host/render_process_host_impl.h
@@ -105,6 +105,7 @@
 class PushMessagingManager;
 class RenderFrameMessageFilter;
 class RenderProcessHostFactory;
+class RenderProcessHostTest;
 class RenderWidgetHelper;
 class SiteInstance;
 class SiteInstanceImpl;
@@ -142,6 +143,9 @@
       public mojom::RendererHost,
       public memory_instrumentation::mojom::CoordinatorConnector {
  public:
+  // The priority of a frame added to the RenderProcessHost.
+  enum class FramePriority { kLow, kNormal };
+
   // Special depth used when there are no PriorityClients.
   static const unsigned int kMaxFrameDepthForPriority;
 
@@ -278,6 +282,13 @@
           header_client,
       network::mojom::URLLoaderFactoryRequest request);
 
+  // Update the total and low priority count as indicated by the previous and
+  // new priorities of the underlying document.  The nullopt option is used when
+  // there is no previous/subsequent navigation (when the frame is added/removed
+  // from the RenderProcessHostImpl).
+  void UpdateFrameWithPriority(base::Optional<FramePriority> previous_priority,
+                               base::Optional<FramePriority> new_priority);
+
   // Call this function when it is evident that the child process is actively
   // performing some operation, for example if we just received an IPC message.
   void mark_child_process_activity_time() {
@@ -455,6 +466,7 @@
   get_render_process_host_factory_for_testing();
 
   // Tracks which sites frames are hosted in which RenderProcessHosts.
+  // TODO(ericrobinson): These don't need to be static.
   static void AddFrameWithSite(BrowserContext* browser_context,
                                RenderProcessHost* render_process_host,
                                const GURL& site_url);
@@ -563,6 +575,7 @@
   friend class ChildProcessLauncherBrowserTest_ChildSpawnFail_Test;
   friend class VisitRelayingRenderProcessHost;
   friend class StoragePartitonInterceptor;
+  friend class RenderProcessHostTest;
 
   // Use CreateRenderProcessHost() instead of calling this constructor
   // directly.
@@ -570,8 +583,13 @@
                         StoragePartitionImpl* storage_partition_impl,
                         bool is_for_guests_only);
 
-  // Initializes a new IPC::ChannelProxy in |channel_|, which will be connected
-  // to the next child process launched for this host, if any.
+  // True if this ChildProcessLauncher has a non-zero number of frames attached
+  // to it and they're all low priority.  Note: This will always return false
+  // unless features::kUseFramePriorityInProcessHost is enabled.
+  bool HasOnlyLowPriorityFrames();
+
+  // Initializes a new IPC::ChannelProxy in |channel_|, which will be
+  // connected to the next child process launched for this host, if any.
   void InitializeChannelProxy();
 
   // Resets |channel_|, removing it from the attachment broker if necessary.
@@ -821,6 +839,12 @@
   // processes of same visibility. It indicates process has frames that
   // intersect with the viewport.
   bool intersects_viewport_ = false;
+  // Tracks the number of low priority frames currently hosted in this process.
+  // Always 0 unless features::kUseFramePriorityInProcessHost is enabled.
+  unsigned int low_priority_frames_ = 0;
+  // Tracks the total number of frames currently hosted in this process.
+  // Always 0 unless features::kUseFramePriorityInProcessHost is enabled.
+  unsigned int total_frames_ = 0;
 #if defined(OS_ANDROID)
   // Highest importance of all clients that contribute priority.
   ChildProcessImportance effective_importance_ = ChildProcessImportance::NORMAL;
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc
index b0505fe..b9004b4 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -397,6 +397,8 @@
     RenderWidgetHostView* parent_host_view,
     const gfx::Rect& bounds_in_screen) {
   DCHECK_EQ(widget_type_, WidgetType::kPopup);
+  DCHECK(!static_cast<RenderWidgetHostViewBase*>(parent_host_view)
+              ->IsRenderWidgetHostViewChildFrame());
 
   popup_parent_host_view_ =
       static_cast<RenderWidgetHostViewAura*>(parent_host_view);
diff --git a/content/browser/service_worker/embedded_worker_instance.cc b/content/browser/service_worker/embedded_worker_instance.cc
index 3bdb94b..9c426ce 100644
--- a/content/browser/service_worker/embedded_worker_instance.cc
+++ b/content/browser/service_worker/embedded_worker_instance.cc
@@ -210,15 +210,13 @@
   }
 
   // Register to DevTools and update params accordingly.
-  // TODO(dgozman): we can now remove this routing id and use something else
-  // as id when talking to ServiceWorkerDevToolsManager.
   const int routing_id = rph->GetNextRoutingID();
   ServiceWorkerDevToolsManager::GetInstance()->WorkerCreated(
       process_id, routing_id, context, weak_context,
       params->service_worker_version_id, params->script_url, params->scope,
       params->is_installed, &params->devtools_worker_token,
       &params->wait_for_debugger);
-  params->worker_devtools_agent_route_id = routing_id;
+  params->service_worker_route_id = routing_id;
   // Create DevToolsProxy here to ensure that the WorkerCreated() call is
   // balanced by DevToolsProxy's destructor calling WorkerDestroyed().
   devtools_proxy = std::make_unique<EmbeddedWorkerInstance::DevToolsProxy>(
@@ -718,7 +716,8 @@
   for (auto& observer : listener_list_)
     observer.OnStarting();
 
-  params->worker_devtools_agent_route_id = MSG_ROUTING_NONE;
+  // service_worker_route_id will be set later in SetupOnUIThread
+  params->service_worker_route_id = MSG_ROUTING_NONE;
   params->wait_for_debugger = false;
   params->subresource_loader_updater =
       subresource_loader_updater_.BindNewPipeAndPassReceiver();
diff --git a/content/browser/service_worker/service_worker_navigation_loader.cc b/content/browser/service_worker/service_worker_navigation_loader.cc
index 68fbe20f..3d10a1e 100644
--- a/content/browser/service_worker/service_worker_navigation_loader.cc
+++ b/content/browser/service_worker/service_worker_navigation_loader.cc
@@ -90,8 +90,8 @@
       "ServiceWorkerNavigationLoader::ServiceWorkerNavigationLoader", this,
       TRACE_EVENT_FLAG_FLOW_OUT);
 
-  response_head_.load_timing.request_start = base::TimeTicks::Now();
-  response_head_.load_timing.request_start_time = base::Time::Now();
+  response_head_->load_timing.request_start = base::TimeTicks::Now();
+  response_head_->load_timing.request_start_time = base::Time::Now();
 }
 
 ServiceWorkerNavigationLoader::~ServiceWorkerNavigationLoader() {
@@ -180,7 +180,7 @@
 
   // Record worker start time here as |fetch_dispatcher_| will start a service
   // worker if there is no running service worker.
-  response_head_.service_worker_start_time = base::TimeTicks::Now();
+  response_head_->service_worker_start_time = base::TimeTicks::Now();
   fetch_dispatcher_->Run();
 }
 
@@ -189,10 +189,10 @@
   TRACE_EVENT_WITH_FLOW2(
       "ServiceWorker", "ServiceWorkerNavigationLoader::CommitResponseHeaders",
       this, TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT,
-      "response_code", response_head_.headers->response_code(), "status_text",
-      response_head_.headers->GetStatusText());
+      "response_code", response_head_->headers->response_code(), "status_text",
+      response_head_->headers->GetStatusText());
   TransitionToStatus(Status::kSentHeader);
-  url_loader_client_->OnReceiveResponse(response_head_);
+  url_loader_client_->OnReceiveResponse(response_head_.Clone());
 }
 
 void ServiceWorkerNavigationLoader::CommitResponseBody(
@@ -247,9 +247,9 @@
   // At this point a service worker is running and the fetch event is about
   // to dispatch. Record some load timings.
   base::TimeTicks now = base::TimeTicks::Now();
-  response_head_.service_worker_ready_time = now;
-  response_head_.load_timing.send_start = now;
-  response_head_.load_timing.send_end = now;
+  response_head_->service_worker_ready_time = now;
+  response_head_->load_timing.send_start = now;
+  response_head_->load_timing.send_end = now;
 
   devtools_attached_ = version->embedded_worker()->devtools_attached();
 }
@@ -329,16 +329,16 @@
   DCHECK_CURRENTLY_ON(ServiceWorkerContext::GetCoreThreadId());
   DCHECK_EQ(status_, Status::kStarted);
 
-  ServiceWorkerLoaderHelpers::SaveResponseInfo(*response, &response_head_);
+  ServiceWorkerLoaderHelpers::SaveResponseInfo(*response, response_head_.get());
   ServiceWorkerLoaderHelpers::SaveResponseHeaders(
       response->status_code, response->status_text, response->headers,
-      &response_head_);
+      response_head_.get());
 
-  response_head_.did_service_worker_navigation_preload =
+  response_head_->did_service_worker_navigation_preload =
       did_navigation_preload_;
-  response_head_.load_timing.receive_headers_start = base::TimeTicks::Now();
-  response_head_.load_timing.receive_headers_end =
-      response_head_.load_timing.receive_headers_start;
+  response_head_->load_timing.receive_headers_start = base::TimeTicks::Now();
+  response_head_->load_timing.receive_headers_end =
+      response_head_->load_timing.receive_headers_start;
   response_source_ = response->response_source;
 
   // Make the navigated page inherit the SSLInfo from its controller service
@@ -347,21 +347,22 @@
   // TODO(horo): When we support mixed-content (HTTP) no-cors requests from a
   // ServiceWorker, we have to check the security level of the responses.
   DCHECK(version->GetMainScriptHttpResponseInfo());
-  response_head_.ssl_info = version->GetMainScriptHttpResponseInfo()->ssl_info;
+  response_head_->ssl_info = version->GetMainScriptHttpResponseInfo()->ssl_info;
 
   // Handle a redirect response. ComputeRedirectInfo returns non-null redirect
   // info if the given response is a redirect.
   base::Optional<net::RedirectInfo> redirect_info =
       ServiceWorkerLoaderHelpers::ComputeRedirectInfo(resource_request_,
-                                                      response_head_);
+                                                      *response_head_);
   if (redirect_info) {
     TRACE_EVENT_WITH_FLOW2(
         "ServiceWorker", "ServiceWorkerNavigationLoader::StartResponse", this,
         TRACE_EVENT_FLAG_FLOW_IN | TRACE_EVENT_FLAG_FLOW_OUT, "result",
         "redirect", "redirect url", redirect_info->new_url.spec());
 
-    response_head_.encoded_data_length = 0;
-    url_loader_client_->OnReceiveRedirect(*redirect_info, response_head_);
+    response_head_->encoded_data_length = 0;
+    url_loader_client_->OnReceiveRedirect(*redirect_info,
+                                          response_head_.Clone());
     // Our client is the navigation loader, which will start a new URLLoader for
     // the redirect rather than calling FollowRedirect(), so we're done here.
     TransitionToStatus(Status::kCompleted);
@@ -489,22 +490,22 @@
   UMA_HISTOGRAM_TIMES(
       "ServiceWorker.LoadTiming.MainFrame.MainResource."
       "StartToForwardServiceWorker",
-      response_head_.service_worker_start_time -
-          response_head_.load_timing.request_start);
+      response_head_->service_worker_start_time -
+          response_head_->load_timing.request_start);
 
   // Time spent for service worker startup.
   UMA_HISTOGRAM_MEDIUM_TIMES(
       "ServiceWorker.LoadTiming.MainFrame.MainResource."
       "ForwardServiceWorkerToWorkerReady2",
-      response_head_.service_worker_ready_time -
-          response_head_.service_worker_start_time);
+      response_head_->service_worker_ready_time -
+          response_head_->service_worker_start_time);
 
   // Browser -> Renderer IPC delay.
   UMA_HISTOGRAM_TIMES(
       "ServiceWorker.LoadTiming.MainFrame.MainResource."
       "WorkerReadyToFetchHandlerStart",
       fetch_event_timing_->dispatch_event_time -
-          response_head_.service_worker_ready_time);
+          response_head_->service_worker_ready_time);
 
   // Time spent by fetch handlers.
   UMA_HISTOGRAM_TIMES(
@@ -518,21 +519,21 @@
     UMA_HISTOGRAM_TIMES(
         "ServiceWorker.LoadTiming.MainFrame.MainResource."
         "FetchHandlerEndToResponseReceived",
-        response_head_.load_timing.receive_headers_end -
+        response_head_->load_timing.receive_headers_end -
             fetch_event_timing_->respond_with_settled_time);
 
     // Time spent reading response body.
     UMA_HISTOGRAM_MEDIUM_TIMES(
         "ServiceWorker.LoadTiming.MainFrame.MainResource."
         "ResponseReceivedToCompleted2",
-        completion_time_ - response_head_.load_timing.receive_headers_end);
+        completion_time_ - response_head_->load_timing.receive_headers_end);
     // Same as above, breakdown by response source.
     base::UmaHistogramMediumTimes(
         base::StrCat({"ServiceWorker.LoadTiming.MainFrame.MainResource."
                       "ResponseReceivedToCompleted2",
                       ServiceWorkerUtils::FetchResponseSourceToSuffix(
                           response_source_)}),
-        completion_time_ - response_head_.load_timing.receive_headers_end);
+        completion_time_ - response_head_->load_timing.receive_headers_end);
   } else {
     // Renderer -> Browser IPC delay (network fallback case).
     UMA_HISTOGRAM_TIMES(
diff --git a/content/browser/service_worker/service_worker_navigation_loader.h b/content/browser/service_worker/service_worker_navigation_loader.h
index 182f27f..8daa07f 100644
--- a/content/browser/service_worker/service_worker_navigation_loader.h
+++ b/content/browser/service_worker/service_worker_navigation_loader.h
@@ -163,7 +163,8 @@
   mojo::Remote<blink::mojom::Blob> body_as_blob_;
 
   bool did_navigation_preload_ = false;
-  network::ResourceResponseHead response_head_;
+  network::mojom::URLResponseHeadPtr response_head_ =
+      network::mojom::URLResponseHead::New();
 
   bool devtools_attached_ = false;
   blink::mojom::ServiceWorkerFetchEventTimingPtr fetch_event_timing_;
diff --git a/content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc b/content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc
index 6ad72f6..b6e3f22 100644
--- a/content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc
+++ b/content/browser/service_worker/service_worker_single_script_update_checker_unittest.cc
@@ -152,13 +152,13 @@
       const std::string& body,
       net::Error error) {
     auto loader_factory = std::make_unique<network::TestURLLoaderFactory>();
-    network::ResourceResponseHead head;
-    head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+    auto head = network::mojom::URLResponseHead::New();
+    head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
         net::HttpUtil::AssembleRawHeaders(header));
-    head.headers->GetMimeType(&head.mime_type);
+    head->headers->GetMimeType(&head->mime_type);
     network::URLLoaderCompletionStatus status(error);
     status.decoded_body_length = body.size();
-    loader_factory->AddResponse(url, head, body, status);
+    loader_factory->AddResponse(url, std::move(head), body, status);
     return loader_factory;
   }
 
@@ -474,11 +474,11 @@
       std::move(loader_factory->GetPendingRequest(0)->client);
 
   // Simulate sending the response head.
-  network::ResourceResponseHead head;
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+  auto head = network::mojom::URLResponseHead::New();
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
       net::HttpUtil::AssembleRawHeaders(kSuccessHeader));
-  head.headers->GetMimeType(&head.mime_type);
-  client->OnReceiveResponse(head);
+  head->headers->GetMimeType(&head->mime_type);
+  client->OnReceiveResponse(std::move(head));
 
   // Simulate sending the response body. The buffer size for the data pipe
   // should be larger than the body to send the whole body in one chunk.
@@ -784,12 +784,11 @@
   // Simulate to send the head and the body back to the checker.
   // Note that OnComplete() is not called yet.
   {
-    network::ResourceResponseHead head =
-        network::CreateResourceResponseHead(net::HTTP_OK);
-    head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+    auto head = network::CreateURLResponseHead(net::HTTP_OK);
+    head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
         net::HttpUtil::AssembleRawHeaders(kSuccessHeader));
-    head.headers->GetMimeType(&head.mime_type);
-    request->client->OnReceiveResponse(head);
+    head->headers->GetMimeType(&head->mime_type);
+    request->client->OnReceiveResponse(std::move(head));
 
     MojoCreateDataPipeOptions options;
     options.struct_size = sizeof(MojoCreateDataPipeOptions);
diff --git a/content/browser/storage_partition_impl_browsertest.cc b/content/browser/storage_partition_impl_browsertest.cc
index ac29404..69cd7ef 100644
--- a/content/browser/storage_partition_impl_browsertest.cc
+++ b/content/browser/storage_partition_impl_browsertest.cc
@@ -21,11 +21,11 @@
 #include "net/http/http_status_code.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/traffic_annotation/network_traffic_annotation_test_helper.h"
-#include "services/network/public/cpp/resource_response_info.h"
 #include "services/network/public/cpp/simple_url_loader.h"
 #include "services/network/public/mojom/network_service.mojom.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 #include "services/network/test/test_url_loader_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
@@ -111,11 +111,11 @@
   // Just wait until headers are received - if the right headers are received,
   // no need to read the body.
   client.RunUntilResponseBodyArrived();
-  ASSERT_TRUE(client.response_head().headers);
-  EXPECT_EQ(200, client.response_head().headers->response_code());
+  ASSERT_TRUE(client.response_head()->headers);
+  EXPECT_EQ(200, client.response_head()->headers->response_code());
 
   std::string foo_header_value;
-  ASSERT_TRUE(client.response_head().headers->GetNormalizedHeader(
+  ASSERT_TRUE(client.response_head()->headers->GetNormalizedHeader(
       "foo", &foo_header_value));
   EXPECT_EQ("bar", foo_header_value);
 }
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
index 5c99617..d951280 100644
--- a/content/browser/web_contents/web_contents_impl.cc
+++ b/content/browser/web_contents/web_contents_impl.cc
@@ -3105,11 +3105,21 @@
   if (!widget_host_view)
     return;
 
-  RenderWidgetHostView* view = nullptr;
-  if (GetOuterWebContents()) {
-    view = GetOuterWebContents()->GetRenderWidgetHostView();
-  } else {
-    view = GetRenderWidgetHostView();
+  // GetOutermostWebContents() returns |this| if there are no outer WebContents.
+  RenderWidgetHostView* view =
+      GetOutermostWebContents()->GetRenderWidgetHostView();
+
+  gfx::Rect transformed_rect(initial_rect);
+  RenderWidgetHostView* this_view = GetRenderWidgetHostView();
+  if (this_view != view) {
+    // We need to transform the coordinates of initial_rect.
+    gfx::Point origin =
+        this_view->TransformPointToRootCoordSpace(initial_rect.origin());
+    gfx::Point bottom_right =
+        this_view->TransformPointToRootCoordSpace(initial_rect.bottom_right());
+    transformed_rect =
+        gfx::Rect(origin.x(), origin.y(), bottom_right.x() - origin.x(),
+                  bottom_right.y() - origin.y());
   }
 
   // Fullscreen child widgets are frames, other child widgets are popups.
@@ -3131,7 +3141,7 @@
     if (!widget_host_view->HasFocus())
       widget_host_view->Focus();
   } else {
-    widget_host_view->InitAsPopup(view, initial_rect);
+    widget_host_view->InitAsPopup(view, transformed_rect);
   }
 
   RenderWidgetHostImpl* render_widget_host_impl = widget_host_view->host();
@@ -7198,6 +7208,13 @@
   return nullptr;
 }
 
+bool WebContentsImpl::IsFrameLowPriority(
+    const RenderFrameHost* render_frame_host) {
+  if (!delegate_)
+    return false;
+  return delegate_->IsFrameLowPriority(this, render_frame_host);
+}
+
 void WebContentsImpl::UpdateWebContentsVisibility(Visibility visibility) {
   // Occlusion is disabled when |features::kWebContentsOcclusion| is disabled
   // (for power and speed impact assessment) or when
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h
index 72f7570..58cf3ba 100644
--- a/content/browser/web_contents/web_contents_impl.h
+++ b/content/browser/web_contents/web_contents_impl.h
@@ -638,6 +638,7 @@
                                    int context_id) override;
   RenderFrameHostImpl* GetMainFrameForInnerDelegate(
       FrameTreeNode* frame_tree_node) override;
+  bool IsFrameLowPriority(const RenderFrameHost* render_frame_host) override;
 
   // RenderViewHostDelegate ----------------------------------------------------
   RenderViewHostDelegateView* GetDelegateView() override;
diff --git a/content/browser/web_package/bundled_exchanges_url_loader_factory_unittest.cc b/content/browser/web_package/bundled_exchanges_url_loader_factory_unittest.cc
index 7ae350c..0c7bebb 100644
--- a/content/browser/web_package/bundled_exchanges_url_loader_factory_unittest.cc
+++ b/content/browser/web_package/bundled_exchanges_url_loader_factory_unittest.cc
@@ -110,11 +110,11 @@
     EXPECT_FALSE(test_client_.has_received_upload_progress());
     EXPECT_FALSE(test_client_.has_received_cached_metadata());
 
-    ASSERT_TRUE(test_client_.response_head().headers);
+    ASSERT_TRUE(test_client_.response_head()->headers);
     ASSERT_TRUE(test_client_.response_body());
 
     EXPECT_EQ(expected_response_code,
-              test_client_.response_head().headers->response_code());
+              test_client_.response_head()->headers->response_code());
 
     if (!expected_body.empty()) {
       std::vector<char> buffer(expected_body.size() * 2);
@@ -192,9 +192,9 @@
   auto loader = CreateLoaderAndStart(std::move(response));
 
   RunAndCheck(206, GetBody().substr(10, 10));
-  EXPECT_EQ(10, GetTestClient().response_head().headers->GetContentLength());
+  EXPECT_EQ(10, GetTestClient().response_head()->headers->GetContentLength());
   std::string content_range;
-  EXPECT_TRUE(GetTestClient().response_head().headers->EnumerateHeader(
+  EXPECT_TRUE(GetTestClient().response_head()->headers->EnumerateHeader(
       nullptr, net::HttpResponseHeaders::kContentRange, &content_range));
   EXPECT_EQ("bytes 10-19/25", content_range);
 }
diff --git a/content/common/background_fetch/background_fetch_types.cc b/content/common/background_fetch/background_fetch_types.cc
index ff307ad..f87695f5 100644
--- a/content/common/background_fetch/background_fetch_types.cc
+++ b/content/common/background_fetch/background_fetch_types.cc
@@ -35,7 +35,8 @@
       CloneSerializedBlob(response->blob), response->error,
       response->response_time, response->cache_storage_cache_name,
       response->cors_exposed_header_names,
-      CloneSerializedBlob(response->side_data_blob));
+      CloneSerializedBlob(response->side_data_blob),
+      response->content_security_policy.Clone());
 }
 
 // static
diff --git a/content/common/frame.mojom b/content/common/frame.mojom
index 94b48f4..9ab40d6 100644
--- a/content/common/frame.mojom
+++ b/content/common/frame.mojom
@@ -260,6 +260,12 @@
   // that allow JS content extended privileges. See BindingsPolicy for valid
   // flag values.
   AllowBindings(int32 enabled_bindings_flags);
+
+  // Used to tell the RenderFrame to enable Mojo JS bindings, which allows
+  // JS code running in the renderer process to connect to Mojo interfaces
+  // and make method calls on them.
+  // This is used for WebUI only at this time.
+  EnableMojoJsBindings();
 };
 
 // Implemented by a service that provides implementations of the Frame
diff --git a/content/common/renderer.mojom b/content/common/renderer.mojom
index fbb4196..c782d9a 100644
--- a/content/common/renderer.mojom
+++ b/content/common/renderer.mojom
@@ -174,16 +174,26 @@
   map<SystemThemeColor, uint32> colors;
 };
 
-enum RenderProcessState {
-  kVisible,
-  // Hidden render processes can still be foregrounded. For example, a hidden
-  // renderer playing audio would be foregrounded.
-  kHidden,
-  // Refers to a renderer that is hidden and running at background process
-  // priority.
+// The background state for the render process.  When backgrounded the process's
+// priority will be lower (via base::Process::SetProcessBackgrounded()) if
+// allowed on the current platform (as determined by
+// base::Process::CanBackgroundProcesses()).
+enum RenderProcessBackgroundState {
+  // The renderer process has not been backgrounded, a hidden renderer may still
+  // be foregrounded, e.g. when it is playing audio.
+  kForegrounded,
+  // The renderer process has been backgrounded, a visible renderer may still
+  // be backgrounded, e.g. when it is hosting only low priority frames.
   kBackgrounded,
 };
 
+// The visibility state for the renderer process, indicating whether or not any
+// of the frames associated with the renderer process are visible.
+enum RenderProcessVisibleState {
+  kVisible,
+  kHidden,
+};
+
 // The primordial Channel-associated interface implemented by a render process.
 // This should be used for implementing browser-to-renderer control messages
 // which need to retain FIFO with respect to legacy IPC messages.
@@ -263,7 +273,8 @@
 
 
   // Tells the renderer process of a change in visibility or background state.
-  SetProcessState(RenderProcessState process_state);
+  SetProcessState(RenderProcessBackgroundState background_state,
+                  RenderProcessVisibleState visible_state);
 
   // Tells the scheduler about "keep-alive" state which can be due to:
   // service workers, shared workers, or fetch keep-alive.
diff --git a/content/common/service_worker/service_worker_loader_helpers.cc b/content/common/service_worker/service_worker_loader_helpers.cc
index 65af54da..1f573ee 100644
--- a/content/common/service_worker/service_worker_loader_helpers.cc
+++ b/content/common/service_worker/service_worker_loader_helpers.cc
@@ -17,9 +17,10 @@
 #include "net/http/http_util.h"
 #include "net/url_request/redirect_util.h"
 #include "services/network/loader_util.h"
+#include "services/network/public/cpp/content_security_policy.h"
 #include "services/network/public/cpp/resource_request.h"
 #include "services/network/public/cpp/resource_request_body.h"
-#include "services/network/public/cpp/resource_response.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 #include "third_party/blink/public/common/blob/blob_utils.h"
 #include "ui/base/page_transition_types.h"
 
@@ -52,7 +53,7 @@
     const int status_code,
     const std::string& status_text,
     const base::flat_map<std::string, std::string>& headers,
-    network::ResourceResponseHead* out_head) {
+    network::mojom::URLResponseHead* out_head) {
   // Build a string instead of using HttpResponseHeaders::AddHeader on
   // each header, since AddHeader has O(n^2) performance.
   std::string buf(base::StringPrintf("HTTP/1.1 %d %s\r\n", status_code,
@@ -93,7 +94,7 @@
 // static
 void ServiceWorkerLoaderHelpers::SaveResponseInfo(
     const blink::mojom::FetchAPIResponse& response,
-    network::ResourceResponseHead* out_head) {
+    network::mojom::URLResponseHead* out_head) {
   out_head->was_fetched_via_service_worker = true;
   out_head->was_fallback_required_by_service_worker = false;
   out_head->url_list_via_service_worker = response.url_list;
@@ -108,13 +109,15 @@
     out_head->cache_storage_cache_name.clear();
   out_head->cors_exposed_header_names = response.cors_exposed_header_names;
   out_head->did_service_worker_navigation_preload = false;
+  out_head->content_security_policy =
+      network::ContentSecurityPolicy(response.content_security_policy.Clone());
 }
 
 // static
 base::Optional<net::RedirectInfo>
 ServiceWorkerLoaderHelpers::ComputeRedirectInfo(
     const network::ResourceRequest& original_request,
-    const network::ResourceResponseHead& response_head) {
+    const network::mojom::URLResponseHead& response_head) {
   std::string new_location;
   if (!response_head.headers->IsRedirect(&new_location))
     return base::nullopt;
diff --git a/content/common/service_worker/service_worker_loader_helpers.h b/content/common/service_worker/service_worker_loader_helpers.h
index f00c5acb..c90564e 100644
--- a/content/common/service_worker/service_worker_loader_helpers.h
+++ b/content/common/service_worker/service_worker_loader_helpers.h
@@ -10,12 +10,12 @@
 #include "mojo/public/cpp/bindings/remote.h"
 #include "net/http/http_request_headers.h"
 #include "net/url_request/redirect_info.h"
+#include "services/network/public/mojom/url_response_head.mojom-forward.h"
 #include "third_party/blink/public/mojom/blob/blob.mojom.h"
 #include "third_party/blink/public/mojom/fetch/fetch_api_response.mojom.h"
 
 namespace network {
 struct ResourceRequest;
-struct ResourceResponseHead;
 }
 
 namespace content {
@@ -30,16 +30,16 @@
       const int status_code,
       const std::string& status_text,
       const base::flat_map<std::string, std::string>& headers,
-      network::ResourceResponseHead* out_head);
+      network::mojom::URLResponseHead* out_head);
   // Populates |out_head| (except for headers) with given |response|.
   static void SaveResponseInfo(const blink::mojom::FetchAPIResponse& response,
-                               network::ResourceResponseHead* out_head);
+                               network::mojom::URLResponseHead* out_head);
 
   // Returns a redirect info if |response_head| is an redirect response.
   // Otherwise returns base::nullopt.
   static base::Optional<net::RedirectInfo> ComputeRedirectInfo(
       const network::ResourceRequest& original_request,
-      const network::ResourceResponseHead& response_head);
+      const network::mojom::URLResponseHead& response_head);
 
   // Reads |blob| into |handle_out|. Calls |on_blob_read_complete| when done or
   // if an error occurred. Currently this always returns net::OK but
diff --git a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectHostImpl.java b/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectHostImpl.java
index 21517f9..2f7bdfb 100644
--- a/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectHostImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/remoteobjects/RemoteObjectHostImpl.java
@@ -83,7 +83,7 @@
     @Override
     public void close() {
         RemoteObjectRegistry registry = mRegistry.get();
-        if (registry != null) {
+        if (registry == null) {
             return;
         }
         registry.close();
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/remoteobjects/RemoteObjectHostImplTest.java b/content/public/android/javatests/src/org/chromium/content/browser/remoteobjects/RemoteObjectHostImplTest.java
index f641f1b..2813ee3 100644
--- a/content/public/android/javatests/src/org/chromium/content/browser/remoteobjects/RemoteObjectHostImplTest.java
+++ b/content/public/android/javatests/src/org/chromium/content/browser/remoteobjects/RemoteObjectHostImplTest.java
@@ -4,6 +4,9 @@
 
 package org.chromium.content.browser.remoteobjects;
 
+import static org.hamcrest.Matchers.isIn;
+import static org.hamcrest.Matchers.not;
+
 import android.support.test.filters.SmallTest;
 
 import org.junit.Assert;
@@ -146,4 +149,15 @@
         host.releaseObject(id);
         Assert.assertNull(mRegistry.getObjectById(id));
     }
+
+    @Test
+    @SmallTest
+    @Feature({"AndroidWebView", "Android-JavaBridge"})
+    public void testClose() {
+        RemoteObjectHostImpl host = new RemoteObjectHostImpl(
+                TestJavascriptInterface.class, /* auditor */ null, mRegistry);
+        Assert.assertThat(mRegistry, isIn(mRetainingSet));
+        host.close();
+        Assert.assertThat(mRegistry, not(isIn(mRetainingSet)));
+    }
 }
diff --git a/content/public/browser/download_manager.h b/content/public/browser/download_manager.h
index d7355b8..0964a78 100644
--- a/content/public/browser/download_manager.h
+++ b/content/public/browser/download_manager.h
@@ -29,6 +29,7 @@
 
 #include <stdint.h>
 
+#include <memory>
 #include <string>
 #include <vector>
 
@@ -46,7 +47,6 @@
 #include "content/common/content_export.h"
 #include "net/base/net_errors.h"
 #include "services/network/public/cpp/shared_url_loader_factory.h"
-#include "storage/browser/blob/blob_data_handle.h"
 #include "url/origin.h"
 
 class GURL;
@@ -119,15 +119,12 @@
       base::Time remove_end) = 0;
 
   using SimpleDownloadManager::DownloadUrl;
-  // For downloads of blob URLs, the caller can pass a BlobDataHandle object so
-  // that the blob will remain valid until the download starts. The
-  // BlobDataHandle will be attached to the associated URLRequest.
-  // If |blob_data_handle| is unspecified, and the blob URL cannot be mapped to
-  // a blob by the time the download request starts, then the download will
-  // fail.
+  // For downloads of blob URLs, the caller can pass a URLLoaderFactory to
+  // use to load the Blob URL. If none is specified and the blob URL cannot be
+  // mapped to a blob by the time the download request starts, then the download
+  // will fail.
   virtual void DownloadUrl(
       std::unique_ptr<download::DownloadUrlParameters> parameters,
-      std::unique_ptr<storage::BlobDataHandle> blob_data_handle,
       scoped_refptr<network::SharedURLLoaderFactory>
           blob_url_loader_factory) = 0;
 
diff --git a/content/public/browser/web_contents_delegate.cc b/content/public/browser/web_contents_delegate.cc
index e6881a1..a69ff67 100644
--- a/content/public/browser/web_contents_delegate.cc
+++ b/content/public/browser/web_contents_delegate.cc
@@ -320,4 +320,11 @@
     WebContents* source) {
   return false;
 }
+
+bool WebContentsDelegate::IsFrameLowPriority(
+    const WebContents* web_contents,
+    const RenderFrameHost* render_frame_host) {
+  return false;
+}
+
 }  // namespace content
diff --git a/content/public/browser/web_contents_delegate.h b/content/public/browser/web_contents_delegate.h
index 70afb53..b882e1b 100644
--- a/content/public/browser/web_contents_delegate.h
+++ b/content/public/browser/web_contents_delegate.h
@@ -675,6 +675,10 @@
   // solid color is displayed instead.
   virtual bool ShouldShowStaleContentOnEviction(WebContents* source);
 
+  // Determine if the frame is of a low priority.
+  virtual bool IsFrameLowPriority(const WebContents* web_contents,
+                                  const RenderFrameHost* render_frame_host);
+
  protected:
   virtual ~WebContentsDelegate();
 
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc
index 238fa57..171d36b 100644
--- a/content/public/common/content_features.cc
+++ b/content/public/common/content_features.cc
@@ -551,6 +551,13 @@
 const base::Feature kTouchpadAsyncPinchEvents{"TouchpadAsyncPinchEvents",
                                               base::FEATURE_ENABLED_BY_DEFAULT};
 
+// Controls whether the RenderProcessHost uses its frames' priorities for
+// determining if it should be backgrounded. When all frames associated with a
+// RenderProcessHost are low priority, that process may be backgrounded even if
+// those frames are visible.
+const base::Feature kUseFramePriorityInRenderProcessHost{
+    "UseFramePriorityInRenderProcessHost", base::FEATURE_DISABLED_BY_DEFAULT};
+
 // Allows developers transfer user activation state to any target window in the
 // frame tree.
 const base::Feature kUserActivationPostMessageTransfer{
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h
index b8aaa14..677a952 100644
--- a/content/public/common/content_features.h
+++ b/content/public/common/content_features.h
@@ -124,6 +124,7 @@
 CONTENT_EXPORT extern const base::Feature kTimerThrottlingForHiddenFrames;
 CONTENT_EXPORT extern const base::Feature kTouchpadAsyncPinchEvents;
 CONTENT_EXPORT extern const base::Feature kTouchpadOverscrollHistoryNavigation;
+CONTENT_EXPORT extern const base::Feature kUseFramePriorityInRenderProcessHost;
 CONTENT_EXPORT extern const base::Feature kUserActivationPostMessageTransfer;
 CONTENT_EXPORT extern const base::Feature kUserActivationSameOriginVisibility;
 CONTENT_EXPORT extern const base::Feature kUserActivationV2;
diff --git a/content/public/test/mock_download_manager.h b/content/public/test/mock_download_manager.h
index 80ca49f5..99a0fec 100644
--- a/content/public/test/mock_download_manager.h
+++ b/content/public/test/mock_download_manager.h
@@ -8,6 +8,7 @@
 #include <stdint.h>
 
 #include <string>
+#include <utility>
 #include <vector>
 
 #include "base/optional.h"
@@ -109,10 +110,9 @@
   MOCK_METHOD1(DownloadUrlMock, void(download::DownloadUrlParameters*));
   void DownloadUrl(
       std::unique_ptr<download::DownloadUrlParameters> params) override {
-    DownloadUrl(std::move(params), nullptr, nullptr);
+    DownloadUrl(std::move(params), nullptr);
   }
   void DownloadUrl(std::unique_ptr<download::DownloadUrlParameters> params,
-                   std::unique_ptr<storage::BlobDataHandle> blob_data_handle,
                    scoped_refptr<network::SharedURLLoaderFactory>
                        blob_url_loader_factory) override {
     DownloadUrlMock(params.get());
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index 79cd638..a81eb70 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -3344,6 +3344,10 @@
   RenderProcess::current()->AddBindings(enabled_bindings_flags);
 }
 
+void RenderFrameImpl::EnableMojoJsBindings() {
+  enable_mojo_js_bindings_ = true;
+}
+
 // mojom::FrameNavigationControl implementation --------------------------------
 
 void RenderFrameImpl::CommitNavigation(
@@ -5554,8 +5558,9 @@
 
 void RenderFrameImpl::DidCreateScriptContext(v8::Local<v8::Context> context,
                                              int world_id) {
-  if ((enabled_bindings_ & BINDINGS_POLICY_MOJO_WEB_UI) && IsMainFrame() &&
-      world_id == ISOLATED_WORLD_ID_GLOBAL) {
+  if (((enabled_bindings_ & BINDINGS_POLICY_MOJO_WEB_UI) ||
+       enable_mojo_js_bindings_) &&
+      IsMainFrame() && world_id == ISOLATED_WORLD_ID_GLOBAL) {
     // We only allow these bindings to be installed when creating the main
     // world context of the main frame.
     blink::WebContextFeatures::EnableMojoJS(context, true);
diff --git a/content/renderer/render_frame_impl.h b/content/renderer/render_frame_impl.h
index f1a995b..1708222 100644
--- a/content/renderer/render_frame_impl.h
+++ b/content/renderer/render_frame_impl.h
@@ -535,6 +535,7 @@
 
   // mojom::FrameBindingsControl implementation:
   void AllowBindings(int32_t enabled_bindings_flags) override;
+  void EnableMojoJsBindings() override;
 
   // mojom::FrameNavigationControl implementation:
   void PostMessageEvent(int32_t source_routing_id,
@@ -1696,6 +1697,10 @@
   // See BindingsPolicy for details.
   int enabled_bindings_ = 0;
 
+  // This boolean indicates whether JS bindings for Mojo should be enabled at
+  // the time the next script context is created.
+  bool enable_mojo_js_bindings_ = false;
+
   service_manager::BindSourceInfo browser_info_;
 
   mojom::FrameHostAssociatedPtr frame_host_ptr_;
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index ac9ff1dc..fe55e45 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -1617,26 +1617,27 @@
 }
 
 void RenderThreadImpl::SetProcessState(
-    mojom::RenderProcessState process_state) {
-  DCHECK(process_state_ != process_state);
+    mojom::RenderProcessBackgroundState background_state,
+    mojom::RenderProcessVisibleState visible_state) {
+  DCHECK(background_state_ != background_state ||
+         visible_state_ != visible_state);
 
-  if (process_state_ == mojom::RenderProcessState::kBackgrounded ||
-      (!process_state_.has_value() &&
-       process_state != mojom::RenderProcessState::kBackgrounded)) {
-    OnRendererForegrounded();
+  if (background_state != background_state_) {
+    if (background_state == mojom::RenderProcessBackgroundState::kForegrounded)
+      OnRendererForegrounded();
+    else
+      OnRendererBackgrounded();
   }
 
-  if (process_state == mojom::RenderProcessState::kVisible) {
-    OnRendererVisible();
-  } else if (process_state_ == mojom::RenderProcessState::kVisible ||
-             !process_state_.has_value()) {
-    OnRendererHidden();
+  if (visible_state != visible_state_) {
+    if (visible_state == mojom::RenderProcessVisibleState::kVisible)
+      OnRendererVisible();
+    else
+      OnRendererHidden();
   }
 
-  if (process_state == mojom::RenderProcessState::kBackgrounded)
-    OnRendererBackgrounded();
-
-  process_state_ = process_state;
+  background_state_ = background_state;
+  visible_state_ = visible_state;
 }
 
 void RenderThreadImpl::SetIsLockedToSite() {
@@ -2299,8 +2300,7 @@
 }
 
 bool RenderThreadImpl::RendererIsHidden() const {
-  return process_state_ == mojom::RenderProcessState::kHidden ||
-         process_state_ == mojom::RenderProcessState::kBackgrounded;
+  return visible_state_ == mojom::RenderProcessVisibleState::kHidden;
 }
 
 void RenderThreadImpl::OnRendererHidden() {
@@ -2320,7 +2320,8 @@
 }
 
 bool RenderThreadImpl::RendererIsBackgrounded() const {
-  return process_state_ == mojom::RenderProcessState::kBackgrounded;
+  return background_state_ ==
+         mojom::RenderProcessBackgroundState::kBackgrounded;
 }
 
 void RenderThreadImpl::OnRendererBackgrounded() {
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index 7cd7d03..65bfa5c 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -511,7 +511,8 @@
   void UpdateSystemColorInfo(
       mojom::UpdateSystemColorInfoParamsPtr params) override;
   void PurgePluginListCache(bool reload_pages) override;
-  void SetProcessState(mojom::RenderProcessState process_state) override;
+  void SetProcessState(mojom::RenderProcessBackgroundState background_state,
+                       mojom::RenderProcessVisibleState visible_state) override;
   void SetSchedulerKeepActive(bool keep_active) override;
   void SetIsLockedToSite() override;
   void EnableV8LowMemoryMode() override;
@@ -577,7 +578,8 @@
   // Used to keep track of the renderer's backgrounded and visibility state.
   // Updated via an IPC from the browser process. If nullopt, the browser
   // process has yet to send an update and the state is unknown.
-  base::Optional<mojom::RenderProcessState> process_state_;
+  base::Optional<mojom::RenderProcessBackgroundState> background_state_;
+  base::Optional<mojom::RenderProcessVisibleState> visible_state_;
 
   blink::WebString user_agent_;
   blink::UserAgentMetadata user_agent_metadata_;
diff --git a/content/renderer/render_thread_impl_browsertest.cc b/content/renderer/render_thread_impl_browsertest.cc
index 129cea20..a7e206f8 100644
--- a/content/renderer/render_thread_impl_browsertest.cc
+++ b/content/renderer/render_thread_impl_browsertest.cc
@@ -239,9 +239,22 @@
  protected:
   IPC::Sender* sender() { return channel_.get(); }
 
-  void SetProcessState(mojom::RenderProcessState process_state) {
+  void SetBackgroundState(
+      mojom::RenderProcessBackgroundState background_state) {
     mojom::Renderer* renderer_interface = thread_;
-    renderer_interface->SetProcessState(process_state);
+    const mojom::RenderProcessVisibleState visible_state =
+        RendererIsHidden() ? mojom::RenderProcessVisibleState::kHidden
+                           : mojom::RenderProcessVisibleState::kVisible;
+    renderer_interface->SetProcessState(background_state, visible_state);
+  }
+
+  void SetVisibleState(mojom::RenderProcessVisibleState visible_state) {
+    mojom::Renderer* renderer_interface = thread_;
+    const mojom::RenderProcessBackgroundState background_state =
+        RendererIsBackgrounded()
+            ? mojom::RenderProcessBackgroundState::kBackgrounded
+            : mojom::RenderProcessBackgroundState::kForegrounded;
+    renderer_interface->SetProcessState(background_state, visible_state);
   }
 
   bool RendererIsBackgrounded() { return thread_->RendererIsBackgrounded(); }
@@ -303,24 +316,18 @@
 }
 
 TEST_F(RenderThreadImplBrowserTest, RendererIsBackgrounded) {
-  SetProcessState(mojom::RenderProcessState::kBackgrounded);
+  SetBackgroundState(mojom::RenderProcessBackgroundState::kBackgrounded);
   EXPECT_TRUE(RendererIsBackgrounded());
 
-  SetProcessState(mojom::RenderProcessState::kHidden);
-  EXPECT_FALSE(RendererIsBackgrounded());
-
-  SetProcessState(mojom::RenderProcessState::kVisible);
+  SetBackgroundState(mojom::RenderProcessBackgroundState::kForegrounded);
   EXPECT_FALSE(RendererIsBackgrounded());
 }
 
 TEST_F(RenderThreadImplBrowserTest, RendererIsHidden) {
-  SetProcessState(mojom::RenderProcessState::kBackgrounded);
+  SetVisibleState(mojom::RenderProcessVisibleState::kHidden);
   EXPECT_TRUE(RendererIsHidden());
 
-  SetProcessState(mojom::RenderProcessState::kHidden);
-  EXPECT_TRUE(RendererIsHidden());
-
-  SetProcessState(mojom::RenderProcessState::kVisible);
+  SetVisibleState(mojom::RenderProcessVisibleState::kVisible);
   EXPECT_FALSE(RendererIsHidden());
 }
 
@@ -331,27 +338,24 @@
   EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false));
   EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(true)).Times(0);
   EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true)).Times(0);
-  SetProcessState(mojom::RenderProcessState::kVisible);
+  SetVisibleState(mojom::RenderProcessVisibleState::kVisible);
   testing::Mock::VerifyAndClear(main_thread_scheduler_);
 
   // Going from a hidden to a visible state should mark the renderer as visible.
-  // A hidden renderer is already foregrounded.
-  SetProcessState(mojom::RenderProcessState::kHidden);
+  SetVisibleState(mojom::RenderProcessVisibleState::kHidden);
   EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false));
   EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(false)).Times(0);
   EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(true)).Times(0);
   EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true)).Times(0);
-  SetProcessState(mojom::RenderProcessState::kVisible);
+  SetVisibleState(mojom::RenderProcessVisibleState::kVisible);
   testing::Mock::VerifyAndClear(main_thread_scheduler_);
 
-  // Going from a backgrounded to a visible state should mark the renderer as
-  // foregrounded and visible.
-  SetProcessState(mojom::RenderProcessState::kBackgrounded);
-  EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(false));
-  EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false));
+  // Going from a visible to a hidden state should mark the renderer as hidden.
+  EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(false)).Times(0);
+  EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false)).Times(0);
   EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(true)).Times(0);
-  EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true)).Times(0);
-  SetProcessState(mojom::RenderProcessState::kVisible);
+  EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true));
+  SetVisibleState(mojom::RenderProcessVisibleState::kHidden);
   testing::Mock::VerifyAndClear(main_thread_scheduler_);
 
   testing::Mock::AllowLeak(main_thread_scheduler_);
@@ -364,27 +368,7 @@
   EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true));
   EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(true)).Times(0);
   EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false)).Times(0);
-  SetProcessState(mojom::RenderProcessState::kHidden);
-  testing::Mock::VerifyAndClear(main_thread_scheduler_);
-
-  // Going from a visible to a hidden state should mark the renderer as hidden.
-  // A visible renderer is already foregrounded.
-  SetProcessState(mojom::RenderProcessState::kVisible);
-  EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true));
-  EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(false)).Times(0);
-  EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false)).Times(0);
-  EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(true)).Times(0);
-  SetProcessState(mojom::RenderProcessState::kHidden);
-  testing::Mock::VerifyAndClear(main_thread_scheduler_);
-
-  // Going from a backgrounded to a hidden state should mark the renderer as
-  // foregrounded and hidden.
-  SetProcessState(mojom::RenderProcessState::kBackgrounded);
-  EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(false));
-  EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true)).Times(0);
-  EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(true)).Times(0);
-  EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false)).Times(0);
-  SetProcessState(mojom::RenderProcessState::kHidden);
+  SetVisibleState(mojom::RenderProcessVisibleState::kHidden);
   testing::Mock::VerifyAndClear(main_thread_scheduler_);
 
   testing::Mock::AllowLeak(main_thread_scheduler_);
@@ -392,32 +376,43 @@
 
 TEST_F(RenderThreadImplBrowserTest, RendererStateTransitionBackgrounded) {
   // Going from an unknown to a backgrounded state should mark the renderer as
-  // hidden and backgrounded.
-  EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true));
+  // backgrounded but not hidden.
+  EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true)).Times(0);
   EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(true));
-  EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false)).Times(0);
+  EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false));
   EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(false)).Times(0);
-  SetProcessState(mojom::RenderProcessState::kBackgrounded);
+  SetBackgroundState(mojom::RenderProcessBackgroundState::kBackgrounded);
   testing::Mock::VerifyAndClear(main_thread_scheduler_);
 
-  // Going from a visible to a backgrounded state should mark the renderer as
-  // hidden and backgrounded.
-  SetProcessState(mojom::RenderProcessState::kVisible);
-  EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true));
-  EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(true));
-  EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false)).Times(0);
-  EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(false)).Times(0);
-  SetProcessState(mojom::RenderProcessState::kBackgrounded);
-  testing::Mock::VerifyAndClear(main_thread_scheduler_);
-
-  // Going from a hidden state to a backgrounded state should mark the renderer
-  // backgrounded. A hidden renderer is already marked as hidden.
-  SetProcessState(mojom::RenderProcessState::kHidden);
-  EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(true));
+  // Going from a backgrounded to a foregrounded state should mark the renderer
+  // as foregrounded.
+  EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(true)).Times(0);
   EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true)).Times(0);
   EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false)).Times(0);
+  EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(false));
+  SetBackgroundState(mojom::RenderProcessBackgroundState::kForegrounded);
+  testing::Mock::VerifyAndClear(main_thread_scheduler_);
+
+  // Going from a foregrounded to a backgrounded state should mark the renderer
+  // as backgrounded.
+  EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true)).Times(0);
+  EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(true));
+  EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false)).Times(0);
   EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(false)).Times(0);
-  SetProcessState(mojom::RenderProcessState::kBackgrounded);
+  SetBackgroundState(mojom::RenderProcessBackgroundState::kBackgrounded);
+  testing::Mock::VerifyAndClear(main_thread_scheduler_);
+
+  testing::Mock::AllowLeak(main_thread_scheduler_);
+}
+
+TEST_F(RenderThreadImplBrowserTest, RendererStateTransitionForegrounded) {
+  // Going from an unknown to a foregrounded state should mark the renderer as
+  // foregrounded and visible.
+  EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(false));
+  EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(true)).Times(0);
+  EXPECT_CALL(*main_thread_scheduler_, SetRendererBackgrounded(true)).Times(0);
+  EXPECT_CALL(*main_thread_scheduler_, SetRendererHidden(false));
+  SetBackgroundState(mojom::RenderProcessBackgroundState::kForegrounded);
   testing::Mock::VerifyAndClear(main_thread_scheduler_);
 
   testing::Mock::AllowLeak(main_thread_scheduler_);
diff --git a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
index 0141d4d..3f26eba 100644
--- a/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
+++ b/content/renderer/service_worker/embedded_worker_instance_client_impl.cc
@@ -89,7 +89,8 @@
       std::move(params->preference_watcher_request),
       std::move(params->subresource_loader_factories),
       std::move(params->subresource_loader_updater),
-      params->script_url_to_skip_throttling, initiator_thread_task_runner_);
+      params->script_url_to_skip_throttling, initiator_thread_task_runner_,
+      params->service_worker_route_id);
   // Record UMA to indicate StartWorker is received on renderer.
   StartWorkerHistogramEnum metric =
       params->is_installed ? StartWorkerHistogramEnum::RECEIVED_ON_INSTALLED
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index 9552400..54dfa3a 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -110,7 +110,8 @@
     mojo::PendingReceiver<blink::mojom::SubresourceLoaderUpdater>
         subresource_loader_updater,
     const GURL& script_url_to_skip_throttling,
-    scoped_refptr<base::SingleThreadTaskRunner> initiator_thread_task_runner)
+    scoped_refptr<base::SingleThreadTaskRunner> initiator_thread_task_runner,
+    int32_t service_worker_route_id)
     : service_worker_version_id_(service_worker_version_id),
       service_worker_scope_(service_worker_scope),
       script_url_(script_url),
@@ -125,7 +126,8 @@
       pending_subresource_loader_updater_(
           std::move(subresource_loader_updater)),
       owner_(owner),
-      start_timing_(std::move(start_timing)) {
+      start_timing_(std::move(start_timing)),
+      service_worker_route_id_(service_worker_route_id) {
   DCHECK(initiator_thread_task_runner_->RunsTasksInCurrentSequence());
   DCHECK(owner_);
   DCHECK(subresource_loaders);
@@ -386,7 +388,7 @@
           ->renderer()
           ->CreateWebSocketHandshakeThrottleProvider(),
       std::move(preference_watcher_receiver_),
-      std::move(pending_subresource_loader_updater_));
+      std::move(pending_subresource_loader_updater_), service_worker_route_id_);
 }
 
 void ServiceWorkerContextClient::OnNavigationPreloadResponse(
diff --git a/content/renderer/service_worker/service_worker_context_client.h b/content/renderer/service_worker/service_worker_context_client.h
index 064263f..224ec6f 100644
--- a/content/renderer/service_worker/service_worker_context_client.h
+++ b/content/renderer/service_worker/service_worker_context_client.h
@@ -108,7 +108,8 @@
       mojo::PendingReceiver<blink::mojom::SubresourceLoaderUpdater>
           subresource_loader_updater,
       const GURL& script_url_to_skip_throttling,
-      scoped_refptr<base::SingleThreadTaskRunner> initiator_thread_task_runner);
+      scoped_refptr<base::SingleThreadTaskRunner> initiator_thread_task_runner,
+      int32_t service_worker_route_id);
   // Called on the initiator thread.
   ~ServiceWorkerContextClient() override;
 
@@ -276,6 +277,8 @@
 
   std::unique_ptr<blink::WebEmbeddedWorker> worker_;
 
+  int32_t service_worker_route_id_;
+
   DISALLOW_COPY_AND_ASSIGN(ServiceWorkerContextClient);
 };
 
diff --git a/content/renderer/service_worker/service_worker_fetch_context_impl.cc b/content/renderer/service_worker/service_worker_fetch_context_impl.cc
index dfa2054..6620f70 100644
--- a/content/renderer/service_worker/service_worker_fetch_context_impl.cc
+++ b/content/renderer/service_worker/service_worker_fetch_context_impl.cc
@@ -33,7 +33,8 @@
     mojo::PendingReceiver<blink::mojom::RendererPreferenceWatcher>
         preference_watcher_receiver,
     mojo::PendingReceiver<blink::mojom::SubresourceLoaderUpdater>
-        pending_subresource_loader_updater)
+        pending_subresource_loader_updater,
+    int32_t service_worker_route_id)
     : renderer_preferences_(renderer_preferences),
       worker_script_url_(worker_script_url),
       url_loader_factory_info_(std::move(url_loader_factory_info)),
@@ -45,7 +46,8 @@
       preference_watcher_pending_receiver_(
           std::move(preference_watcher_receiver)),
       pending_subresource_loader_updater_(
-          std::move(pending_subresource_loader_updater)) {}
+          std::move(pending_subresource_loader_updater)),
+      service_worker_route_id_(service_worker_route_id) {}
 
 ServiceWorkerFetchContextImpl::~ServiceWorkerFetchContextImpl() {}
 
@@ -110,6 +112,7 @@
   }
   auto extra_data = std::make_unique<RequestExtraData>();
   extra_data->set_originated_from_service_worker(true);
+  extra_data->set_render_frame_id(service_worker_route_id_);
 
   const bool needs_to_skip_throttling =
       static_cast<GURL>(request.Url()) == script_url_to_skip_throttling_ &&
diff --git a/content/renderer/service_worker/service_worker_fetch_context_impl.h b/content/renderer/service_worker/service_worker_fetch_context_impl.h
index 21651514..24dcb75 100644
--- a/content/renderer/service_worker/service_worker_fetch_context_impl.h
+++ b/content/renderer/service_worker/service_worker_fetch_context_impl.h
@@ -50,7 +50,8 @@
       mojo::PendingReceiver<blink::mojom::RendererPreferenceWatcher>
           preference_watcher_receiver,
       mojo::PendingReceiver<blink::mojom::SubresourceLoaderUpdater>
-          pending_subresource_loader_updater);
+          pending_subresource_loader_updater,
+      int32_t service_worker_route_id);
 
   // blink::WebWorkerFetchContext implementation:
   void SetTerminateSyncLoadEvent(base::WaitableEvent*) override;
@@ -123,6 +124,8 @@
   base::WaitableEvent* terminate_sync_load_event_ = nullptr;
 
   blink::AcceptLanguagesWatcher* accept_languages_watcher_ = nullptr;
+
+  int32_t service_worker_route_id_;
 };
 
 }  // namespace content
diff --git a/content/renderer/service_worker/service_worker_fetch_context_impl_unittest.cc b/content/renderer/service_worker/service_worker_fetch_context_impl_unittest.cc
index 67f1086..63ebc77 100644
--- a/content/renderer/service_worker/service_worker_fetch_context_impl_unittest.cc
+++ b/content/renderer/service_worker/service_worker_fetch_context_impl_unittest.cc
@@ -48,7 +48,8 @@
       /*script_loader_factory_info=*/nullptr, kScriptUrlToSkipThrottling,
       std::make_unique<FakeURLLoaderThrottleProvider>(),
       /*websocket_handshake_throttle_provider=*/nullptr, mojo::NullReceiver(),
-      mojo::NullReceiver());
+      mojo::NullReceiver(),
+      /*service_worker_route_id=*/-1);
 
   {
     // Call WillSendRequest() for kScriptURL.
diff --git a/content/renderer/service_worker/service_worker_subresource_loader.cc b/content/renderer/service_worker/service_worker_subresource_loader.cc
index 36a584e8..8917971 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader.cc
@@ -46,14 +46,13 @@
 constexpr char kServiceWorkerSubresourceLoaderScope[] =
     "ServiceWorkerSubresourceLoader";
 
-network::ResourceResponseHead RewriteServiceWorkerTime(
+network::mojom::URLResponseHeadPtr RewriteServiceWorkerTime(
     base::TimeTicks service_worker_start_time,
     base::TimeTicks service_worker_ready_time,
-    const network::ResourceResponseHead& response_head) {
-  network::ResourceResponseHead new_head = response_head;
-  new_head.service_worker_start_time = service_worker_start_time;
-  new_head.service_worker_ready_time = service_worker_ready_time;
-  return new_head;
+    network::mojom::URLResponseHeadPtr response_head) {
+  response_head->service_worker_start_time = service_worker_start_time;
+  response_head->service_worker_ready_time = service_worker_ready_time;
+  return response_head;
 }
 
 // A wrapper URLLoaderClient that invokes the given RewriteHeaderCallback
@@ -61,8 +60,8 @@
 class HeaderRewritingURLLoaderClient : public network::mojom::URLLoaderClient {
  public:
   using RewriteHeaderCallback =
-      base::RepeatingCallback<network::ResourceResponseHead(
-          const network::ResourceResponseHead&)>;
+      base::RepeatingCallback<network::mojom::URLResponseHeadPtr(
+          network::mojom::URLResponseHeadPtr)>;
 
   HeaderRewritingURLLoaderClient(
       network::mojom::URLLoaderClientPtr url_loader_client,
@@ -77,7 +76,7 @@
       network::mojom::URLResponseHeadPtr response_head) override {
     DCHECK(url_loader_client_.is_bound());
     url_loader_client_->OnReceiveResponse(
-        rewrite_header_callback_.Run(response_head));
+        rewrite_header_callback_.Run(std::move(response_head)));
   }
 
   void OnReceiveRedirect(
@@ -85,7 +84,7 @@
       network::mojom::URLResponseHeadPtr response_head) override {
     DCHECK(url_loader_client_.is_bound());
     url_loader_client_->OnReceiveRedirect(
-        redirect_info, rewrite_header_callback_.Run(response_head));
+        redirect_info, rewrite_header_callback_.Run(std::move(response_head)));
   }
 
   void OnUploadProgress(int64_t current_position,
@@ -179,9 +178,9 @@
       task_runner_(std::move(task_runner)),
       response_source_(network::mojom::FetchResponseSource::kUnspecified) {
   DCHECK(controller_connector_);
-  response_head_.request_start = base::TimeTicks::Now();
-  response_head_.load_timing.request_start = base::TimeTicks::Now();
-  response_head_.load_timing.request_start_time = base::Time::Now();
+  response_head_->request_start = base::TimeTicks::Now();
+  response_head_->load_timing.request_start = base::TimeTicks::Now();
+  response_head_->load_timing.request_start_time = base::Time::Now();
   // base::Unretained() is safe since |url_loader_binding_| is owned by |this|.
   url_loader_binding_.set_connection_error_handler(
       base::BindOnce(&ServiceWorkerSubresourceLoader::OnConnectionError,
@@ -216,7 +215,7 @@
   // time to set workerStart, since it will either started soon or the fetch
   // event will be dispatched soon.
   // https://w3c.github.io/resource-timing/#dom-performanceresourcetiming-workerstart
-  response_head_.service_worker_start_time = base::TimeTicks::Now();
+  response_head_->service_worker_start_time = base::TimeTicks::Now();
   DispatchFetchEvent();
 }
 
@@ -229,8 +228,8 @@
       controller_connector_->GetControllerServiceWorker(
           blink::mojom::ControllerServiceWorkerPurpose::FETCH_SUB_RESOURCE);
 
-  response_head_.load_timing.send_start = base::TimeTicks::Now();
-  response_head_.load_timing.send_end = base::TimeTicks::Now();
+  response_head_->load_timing.send_start = base::TimeTicks::Now();
+  response_head_->load_timing.send_end = base::TimeTicks::Now();
 
   TRACE_EVENT1("ServiceWorker",
                "ServiceWorkerSubresourceLoader::DispatchFetchEvent",
@@ -394,10 +393,10 @@
     //  Add "Service Worker Fallback Required" which DevTools knows means to not
     //  show the response in the Network tab as it's just an internal
     //  implementation mechanism.
-    response_head_.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+    response_head_->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
         "HTTP/1.1 400 Service Worker Fallback Required");
-    response_head_.was_fetched_via_service_worker = true;
-    response_head_.was_fallback_required_by_service_worker = true;
+    response_head_->was_fetched_via_service_worker = true;
+    response_head_->was_fallback_required_by_service_worker = true;
     CommitResponseHeaders();
     CommitEmptyResponseAndComplete();
     return;
@@ -413,8 +412,8 @@
   auto client_impl = std::make_unique<HeaderRewritingURLLoaderClient>(
       std::move(url_loader_client_),
       base::BindRepeating(&RewriteServiceWorkerTime,
-                          response_head_.service_worker_start_time,
-                          response_head_.service_worker_ready_time));
+                          response_head_->service_worker_start_time,
+                          response_head_->service_worker_ready_time));
   mojo::MakeStrongBinding(std::move(client_impl), mojo::MakeRequest(&client));
 
   fallback_factory_->CreateLoaderAndStart(
@@ -436,7 +435,7 @@
   // |service_worker_ready_time| becomes web-exposed
   // PerformanceResourceTiming#fetchStart, which is the time just before
   // dispatching the fetch event, so set it to |dispatch_event_time|.
-  response_head_.service_worker_ready_time = timing->dispatch_event_time;
+  response_head_->service_worker_ready_time = timing->dispatch_event_time;
   fetch_event_timing_ = std::move(timing);
 }
 
@@ -450,27 +449,28 @@
     return;
   }
 
-  ServiceWorkerLoaderHelpers::SaveResponseInfo(*response, &response_head_);
+  ServiceWorkerLoaderHelpers::SaveResponseInfo(*response, response_head_.get());
   ServiceWorkerLoaderHelpers::SaveResponseHeaders(
       response->status_code, response->status_text, response->headers,
-      &response_head_);
-  response_head_.response_start = base::TimeTicks::Now();
-  response_head_.load_timing.receive_headers_start = base::TimeTicks::Now();
-  response_head_.load_timing.receive_headers_end =
-      response_head_.load_timing.receive_headers_start;
+      response_head_.get());
+  response_head_->response_start = base::TimeTicks::Now();
+  response_head_->load_timing.receive_headers_start = base::TimeTicks::Now();
+  response_head_->load_timing.receive_headers_end =
+      response_head_->load_timing.receive_headers_start;
   response_source_ = response->response_source;
 
   // Handle a redirect response. ComputeRedirectInfo returns non-null redirect
   // info if the given response is a redirect.
   redirect_info_ = ServiceWorkerLoaderHelpers::ComputeRedirectInfo(
-      resource_request_, response_head_);
+      resource_request_, *response_head_);
   if (redirect_info_) {
     if (redirect_limit_-- == 0) {
       CommitCompleted(net::ERR_TOO_MANY_REDIRECTS);
       return;
     }
-    response_head_.encoded_data_length = 0;
-    url_loader_client_->OnReceiveRedirect(*redirect_info_, response_head_);
+    response_head_->encoded_data_length = 0;
+    url_loader_client_->OnReceiveRedirect(*redirect_info_,
+                                          response_head_.Clone());
     TransitionToStatus(Status::kSentRedirect);
     return;
   }
@@ -529,7 +529,7 @@
   TransitionToStatus(Status::kSentHeader);
   DCHECK(url_loader_client_.is_bound());
   // TODO(kinuko): Fill the ssl_info.
-  url_loader_client_->OnReceiveResponse(response_head_);
+  url_loader_client_->OnReceiveResponse(response_head_.Clone());
 }
 
 void ServiceWorkerSubresourceLoader::CommitResponseBody(
@@ -560,7 +560,7 @@
       TRACE_EVENT_FLAG_FLOW_IN, "error_code", net::ErrorToString(error_code));
 
   if (error_code == net::OK) {
-    bool handled = !response_head_.was_fallback_required_by_service_worker;
+    bool handled = !response_head_->was_fallback_required_by_service_worker;
     RecordTimingMetrics(handled);
   }
 
@@ -600,15 +600,15 @@
   UMA_HISTOGRAM_TIMES(
       "ServiceWorker.LoadTiming.Subresource."
       "ForwardServiceWorkerToWorkerReady",
-      response_head_.service_worker_ready_time -
-          response_head_.service_worker_start_time);
+      response_head_->service_worker_ready_time -
+          response_head_->service_worker_start_time);
 
   // Time spent by fetch handlers.
   UMA_HISTOGRAM_TIMES(
       "ServiceWorker.LoadTiming.Subresource."
       "WorkerReadyToFetchHandlerEnd",
       fetch_event_timing_->respond_with_settled_time -
-          response_head_.service_worker_ready_time);
+          response_head_->service_worker_ready_time);
 
   if (handled) {
     // Mojo message delay. If the controller service worker lives in the same
@@ -618,21 +618,21 @@
     UMA_HISTOGRAM_TIMES(
         "ServiceWorker.LoadTiming.Subresource."
         "FetchHandlerEndToResponseReceived",
-        response_head_.load_timing.receive_headers_end -
+        response_head_->load_timing.receive_headers_end -
             fetch_event_timing_->respond_with_settled_time);
 
     // Time spent reading response body.
     UMA_HISTOGRAM_MEDIUM_TIMES(
         "ServiceWorker.LoadTiming.Subresource."
         "ResponseReceivedToCompleted2",
-        completion_time - response_head_.load_timing.receive_headers_end);
+        completion_time - response_head_->load_timing.receive_headers_end);
     // Same as above, breakdown by response source.
     base::UmaHistogramMediumTimes(
         base::StrCat({"ServiceWorker.LoadTiming.Subresource."
                       "ResponseReceivedToCompleted2",
                       ServiceWorkerUtils::FetchResponseSourceToSuffix(
                           response_source_)}),
-        completion_time - response_head_.load_timing.receive_headers_end);
+        completion_time - response_head_->load_timing.receive_headers_end);
   } else {
     // Mojo message delay (network fallback case). See above for the detail.
     UMA_HISTOGRAM_TIMES(
@@ -734,7 +734,7 @@
   DCHECK(data_pipe.is_valid());
 
   base::TimeDelta delay =
-      base::TimeTicks::Now() - response_head_.response_start;
+      base::TimeTicks::Now() - response_head_->response_start;
   UMA_HISTOGRAM_TIMES(
       "ServiceWorker.SubresourceNotifyStartLoadingResponseBodyDelay", delay);
 
diff --git a/content/renderer/service_worker/service_worker_subresource_loader.h b/content/renderer/service_worker/service_worker_subresource_loader.h
index c6e30eb6..36063d7d 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader.h
+++ b/content/renderer/service_worker/service_worker_subresource_loader.h
@@ -17,7 +17,6 @@
 #include "mojo/public/cpp/bindings/remote.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/redirect_info.h"
-#include "services/network/public/cpp/resource_response.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
 #include "third_party/blink/public/common/service_worker/service_worker_status_code.h"
 #include "third_party/blink/public/mojom/blob/blob.mojom.h"
@@ -143,7 +142,8 @@
 
   void TransitionToStatus(Status new_status);
 
-  network::ResourceResponseHead response_head_;
+  network::mojom::URLResponseHeadPtr response_head_ =
+      network::mojom::URLResponseHead::New();
   base::Optional<net::RedirectInfo> redirect_info_;
   int redirect_limit_;
 
diff --git a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
index f0e17b08..2a3b80f 100644
--- a/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
+++ b/content/renderer/service_worker/service_worker_subresource_loader_unittest.cc
@@ -430,11 +430,10 @@
   DISALLOW_COPY_AND_ASSIGN(FakeServiceWorkerContainerHost);
 };
 
-// Returns an expected ResourceResponseHead which is used by stream response
-// related tests.
-std::unique_ptr<network::ResourceResponseHead>
-CreateResponseInfoFromServiceWorker() {
-  auto head = std::make_unique<network::ResourceResponseHead>();
+// Returns an expected network::mojom::URLResponseHeadPtr which is used by
+// stream response related tests.
+network::mojom::URLResponseHeadPtr CreateResponseInfoFromServiceWorker() {
+  auto head = network::mojom::URLResponseHead::New();
   std::string headers = "HTTP/1.1 200 OK\n\n";
   head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
       net::HttpUtil::AssembleRawHeaders(headers));
@@ -501,8 +500,9 @@
         net::MutableNetworkTrafficAnnotationTag(TRAFFIC_ANNOTATION_FOR_TESTS));
   }
 
-  void ExpectResponseInfo(const network::ResourceResponseHead& info,
-                          const network::ResourceResponseHead& expected_info) {
+  void ExpectResponseInfo(
+      const network::mojom::URLResponseHead& info,
+      const network::mojom::URLResponseHead& expected_info) {
     EXPECT_EQ(expected_info.headers->response_code(),
               info.headers->response_code());
     EXPECT_EQ(expected_info.was_fetched_via_service_worker,
@@ -620,7 +620,7 @@
 
   client->RunUntilComplete();
 
-  net::LoadTimingInfo load_timing_info = client->response_head().load_timing;
+  net::LoadTimingInfo load_timing_info = client->response_head()->load_timing;
   EXPECT_FALSE(load_timing_info.receive_headers_start.is_null());
   EXPECT_FALSE(load_timing_info.receive_headers_end.is_null());
   EXPECT_LE(load_timing_info.receive_headers_start,
@@ -753,7 +753,7 @@
     client->RunUntilComplete();
 
     EXPECT_TRUE(client->has_received_completion());
-    EXPECT_FALSE(client->response_head().was_fetched_via_service_worker);
+    EXPECT_FALSE(client->response_head()->was_fetched_via_service_worker);
 
     EXPECT_EQ(1, fake_controller_.fetch_event_count());
     EXPECT_EQ(1, fake_container_host_.get_controller_service_worker_count());
@@ -889,8 +889,8 @@
   StartRequest(factory, request, &loader, &client);
   client->RunUntilResponseReceived();
 
-  const network::ResourceResponseHead& info = client->response_head();
-  ExpectResponseInfo(info, *CreateResponseInfoFromServiceWorker());
+  auto& info = client->response_head();
+  ExpectResponseInfo(*info, *CreateResponseInfoFromServiceWorker());
 
   // Write the body stream.
   uint32_t written_bytes = sizeof(kResponseBody) - 1;
@@ -948,8 +948,8 @@
   StartRequest(factory, request, &loader, &client);
   client->RunUntilResponseReceived();
 
-  const network::ResourceResponseHead& info = client->response_head();
-  ExpectResponseInfo(info, *CreateResponseInfoFromServiceWorker());
+  auto& info = client->response_head();
+  ExpectResponseInfo(*info, *CreateResponseInfoFromServiceWorker());
 
   // Start writing the body stream, then abort before finishing.
   uint32_t written_bytes = sizeof(kResponseBody) - 1;
@@ -1005,14 +1005,13 @@
   StartRequest(factory, request, &loader, &client);
   client->RunUntilResponseReceived();
 
-  std::unique_ptr<network::ResourceResponseHead> expected_info =
-      CreateResponseInfoFromServiceWorker();
+  auto expected_info = CreateResponseInfoFromServiceWorker();
   // |is_in_cache_storage| should be true because |fake_controller_| sets the
   // response source as CacheStorage.
   expected_info->is_in_cache_storage = true;
-  const network::ResourceResponseHead& info = client->response_head();
-  ExpectResponseInfo(info, *expected_info);
-  EXPECT_EQ(39, info.content_length);
+  auto& info = client->response_head();
+  ExpectResponseInfo(*info, *expected_info);
+  EXPECT_EQ(39, info->content_length);
 
   // Test the cached metadata.
   client->RunUntilCachedMetadataReceived();
@@ -1063,8 +1062,8 @@
   StartRequest(factory, request, &loader, &client);
   client->RunUntilResponseReceived();
 
-  const network::ResourceResponseHead& info = client->response_head();
-  ExpectResponseInfo(info, *CreateResponseInfoFromServiceWorker());
+  auto& info = client->response_head();
+  ExpectResponseInfo(*info, *CreateResponseInfoFromServiceWorker());
 
   client->RunUntilComplete();
   EXPECT_EQ(net::OK, client->completion_status().error_code);
@@ -1110,14 +1109,13 @@
   StartRequest(factory, request, &loader, &client);
   client->RunUntilResponseReceived();
 
-  std::unique_ptr<network::ResourceResponseHead> expected_info =
-      CreateResponseInfoFromServiceWorker();
+  auto expected_info = CreateResponseInfoFromServiceWorker();
   // |is_in_cache_storage| should be true because |fake_controller_| sets the
   // response source as CacheStorage.
   expected_info->is_in_cache_storage = true;
-  const network::ResourceResponseHead& info = client->response_head();
-  ExpectResponseInfo(info, *expected_info);
-  EXPECT_EQ(33, info.content_length);
+  auto& info = client->response_head();
+  ExpectResponseInfo(*info, *expected_info);
+  EXPECT_EQ(33, info->content_length);
 
   client->RunUntilComplete();
   EXPECT_EQ(net::OK, client->completion_status().error_code);
@@ -1153,7 +1151,7 @@
 
   // OnFallback() should complete the network request using network loader.
   EXPECT_TRUE(client->has_received_completion());
-  EXPECT_FALSE(client->response_head().was_fetched_via_service_worker);
+  EXPECT_FALSE(client->response_head()->was_fetched_via_service_worker);
 
   histogram_tester.ExpectUniqueSample(kHistogramSubresourceFetchEvent,
                                       blink::ServiceWorkerStatusCode::kOk, 1);
@@ -1244,9 +1242,9 @@
   loader->FollowRedirect({}, {}, base::nullopt);
   client->RunUntilResponseReceived();
 
-  const network::ResourceResponseHead& info = client->response_head();
-  EXPECT_EQ(200, info.headers->response_code());
-  EXPECT_EQ(network::mojom::FetchResponseType::kDefault, info.response_type);
+  auto& info = client->response_head();
+  EXPECT_EQ(200, info->headers->response_code());
+  EXPECT_EQ(network::mojom::FetchResponseType::kDefault, info->response_type);
 
   // Write the body stream.
   uint32_t written_bytes = sizeof(kResponseBody) - 1;
@@ -1391,14 +1389,14 @@
     StartRequest(factory, request, &loader, &client);
     client->RunUntilComplete();
 
-    const network::ResourceResponseHead& info = client->response_head();
+    auto& info = client->response_head();
     EXPECT_EQ(test.expected_was_fallback_required_by_service_worker,
-              info.was_fetched_via_service_worker);
+              info->was_fetched_via_service_worker);
     EXPECT_EQ(test.expected_was_fallback_required_by_service_worker,
-              info.was_fallback_required_by_service_worker);
-    if (info.was_fallback_required_by_service_worker) {
+              info->was_fallback_required_by_service_worker);
+    if (info->was_fallback_required_by_service_worker) {
       EXPECT_EQ("HTTP/1.1 400 Service Worker Fallback Required",
-                info.headers->GetStatusLine());
+                info->headers->GetStatusLine());
     }
     histogram_tester.ExpectTotalCount(
         "ServiceWorker.LoadTiming.Subresource."
@@ -1440,10 +1438,10 @@
   EXPECT_EQ(net::OK, client->completion_status().error_code);
 
   // Test the response.
-  const network::ResourceResponseHead& info = client->response_head();
-  ExpectResponseInfo(info, *CreateResponseInfoFromServiceWorker());
-  EXPECT_EQ(33, info.content_length);
-  EXPECT_FALSE(info.headers->HasHeader("Content-Range"));
+  auto& info = client->response_head();
+  ExpectResponseInfo(*info, *CreateResponseInfoFromServiceWorker());
+  EXPECT_EQ(33, info->content_length);
+  EXPECT_FALSE(info->headers->HasHeader("Content-Range"));
   EXPECT_EQ(kResponseBody, TakeResponseBody(client.get()));
 }
 
@@ -1461,12 +1459,12 @@
   EXPECT_EQ(net::OK, client->completion_status().error_code);
 
   // Test the response.
-  const network::ResourceResponseHead& info = client->response_head();
-  EXPECT_EQ(206, info.headers->response_code());
+  auto& info = client->response_head();
+  EXPECT_EQ(206, info->headers->response_code());
   std::string range;
-  ASSERT_TRUE(info.headers->GetNormalizedHeader("Content-Range", &range));
+  ASSERT_TRUE(info->headers->GetNormalizedHeader("Content-Range", &range));
   EXPECT_EQ("bytes 5-13/33", range);
-  EXPECT_EQ(9, info.content_length);
+  EXPECT_EQ(9, info->content_length);
   EXPECT_EQ("is sample", TakeResponseBody(client.get()));
 }
 
@@ -1485,12 +1483,12 @@
   EXPECT_EQ(net::OK, client->completion_status().error_code);
 
   // Test the response.
-  const network::ResourceResponseHead& info = client->response_head();
-  EXPECT_EQ(206, info.headers->response_code());
+  auto& info = client->response_head();
+  EXPECT_EQ(206, info->headers->response_code());
   std::string range;
-  ASSERT_TRUE(info.headers->GetNormalizedHeader("Content-Range", &range));
+  ASSERT_TRUE(info->headers->GetNormalizedHeader("Content-Range", &range));
   EXPECT_EQ("bytes 5-32/33", range);
-  EXPECT_EQ(28, info.content_length);
+  EXPECT_EQ(28, info->content_length);
   EXPECT_EQ("is sample text for the Blob.", TakeResponseBody(client.get()));
 }
 
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index 223ed71..ab524338 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -992,6 +992,7 @@
     "../browser/pointer_lock_browsertest_mac.mm",
     "../browser/portal/portal_browsertest.cc",
     "../browser/power_monitor_browsertest.cc",
+    "../browser/process_internals/process_internals_browsertest.cc",
     "../browser/renderer_host/input/autoscroll_browsertest.cc",
     "../browser/renderer_host/input/composited_scrolling_browsertest.cc",
     "../browser/renderer_host/input/compositor_event_ack_browsertest.cc",
diff --git a/content/test/gpu/gpu_tests/pixel_integration_test.py b/content/test/gpu/gpu_tests/pixel_integration_test.py
index 06d29cf..7daa2eb7 100644
--- a/content/test/gpu/gpu_tests/pixel_integration_test.py
+++ b/content/test/gpu/gpu_tests/pixel_integration_test.py
@@ -2,6 +2,7 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+from datetime import date
 import json
 import logging
 import os
@@ -427,8 +428,30 @@
                           SKIA_GOLD_INSTANCE, image_name))
         logging.error(
             'Approved images for %s in Gold: %s', image_name, gold_images)
-      if not parsed_options.no_skia_gold_failure:
-        raise Exception('goldctl command failed')
+      if self._ShouldReportGoldFailure(page):
+        raise Exception('goldctl command failed, see above for details')
+
+  def _ShouldReportGoldFailure(self, page):
+    """Determines if a Gold failure should actually be surfaced.
+
+    Args:
+      page: The GPU PixelTestPage object for the test.
+
+    Returns:
+      True if the failure should be surfaced, i.e. the test should fail,
+      otherwise False.
+    """
+    parsed_options = self.GetParsedCommandLineOptions()
+    # Don't surface if we're explicitly told not to.
+    if parsed_options.no_skia_gold_failure:
+      return False
+    # Don't surface if the test was recently added and we're still within its
+    # grace period. However, fail if we're on a trybot so that as many images
+    # can be triaged as possible before a new test is committed.
+    if (page.grace_period_end and date.today() <= page.grace_period_end and
+        not parsed_options.review_patch_issue):
+      return False
+    return True
 
   def _ValidateScreenshotSamplesWithSkiaGold(self, tab, page, screenshot,
                                              device_pixel_ratio,
diff --git a/content/test/gpu/gpu_tests/pixel_test_pages.py b/content/test/gpu/gpu_tests/pixel_test_pages.py
index 2a05bd96..9efd1eda 100644
--- a/content/test/gpu/gpu_tests/pixel_test_pages.py
+++ b/content/test/gpu/gpu_tests/pixel_test_pages.py
@@ -37,7 +37,7 @@
   def __init__(self, url, name, test_rect, revision,
                tolerance=2, browser_args=None, expected_colors=None,
                gpu_process_disabled=False, optional_action=None,
-               other_args=None):
+               other_args=None, grace_period_end=None):
     super(PixelTestPage, self).__init__()
     self.url = url
     self.name = name
@@ -66,6 +66,12 @@
     # VideoPathTraceTest and OverlayModeTest support the following boolean
     # arguments: expect_yuy2, zero_copy, video_is_rotated, and no_overlay.
     self.other_args = other_args
+    # This allows a newly added test to be exempted from failures for a
+    # (hopefully) short period after being added. This is so that any slightly
+    # different but valid images that get produced by the waterfall bots can
+    # be triaged without turning the bots red.
+    # This should be a datetime.date object.
+    self.grace_period_end = grace_period_end
 
   def CopyWithNewBrowserArgsAndSuffix(self, browser_args, suffix):
     return PixelTestPage(
diff --git a/content/test/url_loader_interceptor_test.cc b/content/test/url_loader_interceptor_test.cc
index 182e13a..69c107b 100644
--- a/content/test/url_loader_interceptor_test.cc
+++ b/content/test/url_loader_interceptor_test.cc
@@ -276,8 +276,8 @@
       "HTTP/1.1 200 OK\nContent-type: text/html\n\n", body, &client);
   client.RunUntilComplete();
 
-  EXPECT_EQ(client.response_head().headers->response_code(), 200);
-  EXPECT_EQ(client.response_head().mime_type, "text/html");
+  EXPECT_EQ(client.response_head()->headers->response_code(), 200);
+  EXPECT_EQ(client.response_head()->mime_type, "text/html");
 
   std::string response;
   EXPECT_TRUE(
@@ -295,7 +295,7 @@
                                       &headers);
   client.RunUntilComplete();
 
-  EXPECT_EQ(client.response_head().headers->response_code(), 404);
+  EXPECT_EQ(client.response_head()->headers->response_code(), 404);
 
   std::string response;
   EXPECT_TRUE(
@@ -311,10 +311,10 @@
   URLLoaderInterceptor::WriteResponse("content/test/data/hello.html", &client);
   client.RunUntilComplete();
 
-  EXPECT_EQ(client.response_head().headers->response_code(), 200);
+  EXPECT_EQ(client.response_head()->headers->response_code(), 200);
 
   std::string mime_type;
-  EXPECT_TRUE(client.response_head().headers->GetMimeType(&mime_type));
+  EXPECT_TRUE(client.response_head()->headers->GetMimeType(&mime_type));
   EXPECT_EQ(mime_type, "text/html");
 
   std::string response;
@@ -330,10 +330,10 @@
   URLLoaderInterceptor::WriteResponse("content/test/data/empty.html", &client);
   client.RunUntilComplete();
 
-  EXPECT_EQ(client.response_head().headers->response_code(), 200);
+  EXPECT_EQ(client.response_head()->headers->response_code(), 200);
 
   std::string mime_type;
-  EXPECT_TRUE(client.response_head().headers->GetMimeType(&mime_type));
+  EXPECT_TRUE(client.response_head()->headers->GetMimeType(&mime_type));
   EXPECT_EQ(mime_type, "text/html");
 
   std::string response;
diff --git a/device/fido/ble/fido_ble_connection.cc b/device/fido/ble/fido_ble_connection.cc
index 235d898..95dadff 100644
--- a/device/fido/ble/fido_ble_connection.cc
+++ b/device/fido/ble/fido_ble_connection.cc
@@ -501,8 +501,6 @@
     // and a caBLE device.
     if (service->GetUUID() == BluetoothUUID(kFidoServiceUUID) ||
         service->GetUUID() == BluetoothUUID(kCableAdvertisementUUID128)) {
-      FIDO_LOG(EVENT) << "Found caBLE service UUID: "
-                      << service->GetUUID().value();
       return service;
     }
   }
diff --git a/device/fido/cable/fido_cable_discovery.cc b/device/fido/cable/fido_cable_discovery.cc
index fe3157c..6f9f8710 100644
--- a/device/fido/cable/fido_cable_discovery.cc
+++ b/device/fido/cable/fido_cable_discovery.cc
@@ -263,13 +263,22 @@
 
 FidoCableDiscovery::Result::Result(const CableDiscoveryData& in_discovery_data,
                                    const CableNonce& in_nonce,
-                                   const CableEidArray& in_eid)
-    : discovery_data(in_discovery_data), nonce(in_nonce), eid(in_eid) {}
+                                   const CableEidArray& in_eid,
+                                   base::Optional<int> in_ticks_back)
+    : discovery_data(in_discovery_data),
+      nonce(in_nonce),
+      eid(in_eid),
+      ticks_back(in_ticks_back) {}
 
 FidoCableDiscovery::Result::Result(const Result& other) = default;
 
 FidoCableDiscovery::Result::~Result() = default;
 
+// FidoCableDiscovery::ObservedDeviceData -------------------------------------
+
+FidoCableDiscovery::ObservedDeviceData::ObservedDeviceData() = default;
+FidoCableDiscovery::ObservedDeviceData::~ObservedDeviceData() = default;
+
 // FidoCableDiscovery ---------------------------------------------------------
 
 FidoCableDiscovery::FidoCableDiscovery(
@@ -347,7 +356,6 @@
   if (!IsCableDevice(device))
     return;
 
-  FIDO_LOG(DEBUG) << "Discovered caBLE device: " << device->GetAddress();
   CableDeviceFound(adapter, device);
 }
 
@@ -356,8 +364,6 @@
   if (!IsCableDevice(device))
     return;
 
-  FIDO_LOG(DEBUG) << "Device changed for caBLE device: "
-                  << device->GetAddress();
   CableDeviceFound(adapter, device);
 }
 
@@ -504,6 +510,7 @@
 
   FIDO_LOG(EVENT) << "Found new caBLE device.";
   active_devices_.insert(device_address);
+  active_authenticator_eids_.insert(maybe_result->eid);
 
   auto cable_device =
       std::make_unique<FidoCableDevice>(adapter, device->GetAddress());
@@ -549,22 +556,63 @@
 
 base::Optional<FidoCableDiscovery::Result>
 FidoCableDiscovery::GetCableDiscoveryData(const BluetoothDevice* device) const {
-  auto maybe_result = GetCableDiscoveryDataFromServiceData(device);
-  if (maybe_result) {
-    FIDO_LOG(DEBUG) << "Found caBLE service data.";
-    return maybe_result;
+  base::Optional<CableEidArray> maybe_eid_from_service_data =
+      MaybeGetEidFromServiceData(device);
+  std::vector<CableEidArray> uuids = GetUUIDs(device);
+
+  const std::string address = device->GetAddress();
+  const auto it = observed_devices_.find(address);
+  const bool known = it != observed_devices_.end();
+  if (known) {
+    std::unique_ptr<ObservedDeviceData>& data = it->second;
+    if (maybe_eid_from_service_data == data->service_data &&
+        uuids == data->uuids) {
+      // Duplicate data. Ignore.
+      return base::nullopt;
+    }
   }
 
-  FIDO_LOG(DEBUG)
-      << "caBLE service data not found. Searching for caBLE UUIDs instead.";
-  // iOS devices cannot advertise service data. These devices instead put the
-  // authenticator EID as a second UUID in addition to the caBLE UUID.
-  return GetCableDiscoveryDataFromServiceUUIDs(device);
+  auto data = std::make_unique<ObservedDeviceData>();
+  data->service_data = maybe_eid_from_service_data;
+  data->uuids = uuids;
+  observed_devices_.emplace(std::make_pair(address, std::move(data)));
+
+  // New or updated device information.
+  if (known) {
+    FIDO_LOG(DEBUG) << "Updated information for caBLE device " << address
+                    << ":";
+  } else {
+    FIDO_LOG(DEBUG) << "New caBLE device " << address << ":";
+  }
+
+  base::Optional<FidoCableDiscovery::Result> ret;
+  if (maybe_eid_from_service_data.has_value()) {
+    ret =
+        GetCableDiscoveryDataFromAuthenticatorEid(*maybe_eid_from_service_data);
+    FIDO_LOG(DEBUG) << "  Service data: "
+                    << ResultDebugString(*maybe_eid_from_service_data, ret);
+
+  } else {
+    FIDO_LOG(DEBUG) << "  Service data: <none>";
+  }
+
+  if (!uuids.empty()) {
+    FIDO_LOG(DEBUG) << "  UUIDs:";
+    for (const auto& uuid : uuids) {
+      auto result = GetCableDiscoveryDataFromAuthenticatorEid(uuid);
+      FIDO_LOG(DEBUG) << "    " << ResultDebugString(uuid, result);
+      if (!ret.has_value() && result.has_value()) {
+        ret = result;
+      }
+    }
+  }
+
+  return ret;
 }
 
-base::Optional<FidoCableDiscovery::Result>
-FidoCableDiscovery::GetCableDiscoveryDataFromServiceData(
-    const BluetoothDevice* device) const {
+// static
+base::Optional<CableEidArray> FidoCableDiscovery::MaybeGetEidFromServiceData(
+    const BluetoothDevice* device) {
   const auto* service_data =
       device->GetServiceDataForUUID(CableAdvertisementUUID());
   if (!service_data) {
@@ -581,19 +629,16 @@
       *service_data, 2, &received_authenticator_eid);
   if (!extract_success)
     return base::nullopt;
-
-  return GetCableDiscoveryDataFromAuthenticatorEid(
-      std::move(received_authenticator_eid));
+  return received_authenticator_eid;
 }
 
-base::Optional<FidoCableDiscovery::Result>
-FidoCableDiscovery::GetCableDiscoveryDataFromServiceUUIDs(
-    const BluetoothDevice* device) const {
+// static
+std::vector<CableEidArray> FidoCableDiscovery::GetUUIDs(
+    const BluetoothDevice* device) {
+  std::vector<CableEidArray> ret;
+
   const auto service_uuids = device->GetUUIDs();
   for (const auto& uuid : service_uuids) {
-    if (uuid == CableAdvertisementUUID())
-      continue;
-
     // |uuid_hex| is a hex string with the format:
     // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
     const std::string& uuid_hex = uuid.canonical_value();
@@ -618,14 +663,10 @@
     memcpy(authenticator_eid.data(), uuid_binary.data(),
            authenticator_eid.size());
 
-    auto maybe_result =
-        GetCableDiscoveryDataFromAuthenticatorEid(authenticator_eid);
-    if (maybe_result) {
-      return maybe_result;
-    }
+    ret.emplace_back(std::move(authenticator_eid));
   }
 
-  return base::nullopt;
+  return ret;
 }
 
 base::Optional<FidoCableDiscovery::Result>
@@ -634,7 +675,7 @@
   for (const auto& candidate : discovery_data_) {
     auto maybe_nonce = candidate.Match(authenticator_eid);
     if (maybe_nonce) {
-      return Result(candidate, *maybe_nonce, authenticator_eid);
+      return Result(candidate, *maybe_nonce, authenticator_eid, base::nullopt);
     }
   }
 
@@ -652,7 +693,7 @@
       CableDiscoveryData candidate(qr_secret);
       auto maybe_nonce = candidate.Match(authenticator_eid);
       if (maybe_nonce) {
-        return Result(candidate, *maybe_nonce, authenticator_eid);
+        return Result(candidate, *maybe_nonce, authenticator_eid, i);
       }
     }
   }
@@ -660,4 +701,69 @@
   return base::nullopt;
 }
 
+// static
+std::string FidoCableDiscovery::ResultDebugString(
+    const CableEidArray& eid,
+    const base::Optional<FidoCableDiscovery::Result>& result) {
+  static const uint8_t kAppleContinuity[16] = {
+      0xd0, 0x61, 0x1e, 0x78, 0xbb, 0xb4, 0x45, 0x91,
+      0xa5, 0xf8, 0x48, 0x79, 0x10, 0xae, 0x43, 0x66,
+  };
+  static const uint8_t kAppleUnknown[16] = {
+      0x9f, 0xa4, 0x80, 0xe0, 0x49, 0x67, 0x45, 0x42,
+      0x93, 0x90, 0xd3, 0x43, 0xdc, 0x5d, 0x04, 0xae,
+  };
+  static const uint8_t kAppleMedia[16] = {
+      0x89, 0xd3, 0x50, 0x2b, 0x0f, 0x36, 0x43, 0x3a,
+      0x8e, 0xf4, 0xc5, 0x02, 0xad, 0x55, 0xf8, 0xdc,
+  };
+  static const uint8_t kAppleNotificationCenter[16] = {
+      0x79, 0x05, 0xf4, 0x31, 0xb5, 0xce, 0x4e, 0x99,
+      0xa4, 0x0f, 0x4b, 0x1e, 0x12, 0x2d, 0x00, 0xd0,
+  };
+  static const uint8_t kCable[16] = {
+      0x00, 0x00, 0xfd, 0xe2, 0x00, 0x00, 0x10, 0x00,
+      0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+  };
+
+  std::string ret = base::HexEncode(eid) + "";
+
+  if (!result) {
+    // Try to identify some common UUIDs that are random and thus otherwise look
+    // like potential EIDs.
+    if (memcmp(eid.data(), kAppleContinuity, eid.size()) == 0) {
+      ret += " (Apple Continuity service)";
+    } else if (memcmp(eid.data(), kAppleUnknown, eid.size()) == 0) {
+      ret += " (Apple service)";
+    } else if (memcmp(eid.data(), kAppleMedia, eid.size()) == 0) {
+      ret += " (Apple Media service)";
+    } else if (memcmp(eid.data(), kAppleNotificationCenter, eid.size()) == 0) {
+      ret += " (Apple Notification service)";
+    } else if (memcmp(eid.data(), kCable, eid.size()) == 0) {
+      ret += " (caBLE indicator)";
+    }
+    return ret;
+  }
+
+  switch (result->discovery_data.version) {
+    case CableDiscoveryData::Version::V1:
+      ret += " (version one match";
+      break;
+    case CableDiscoveryData::Version::V2:
+      ret += " (version two match";
+      break;
+    case CableDiscoveryData::Version::INVALID:
+      NOTREACHED();
+  }
+
+  if (!result->ticks_back) {
+    ret += " against pairing data)";
+  } else {
+    ret += " from QR, " + base::NumberToString(*result->ticks_back) +
+           " tick(s) ago)";
+  }
+
+  return ret;
+}
+
 }  // namespace device
diff --git a/device/fido/cable/fido_cable_discovery.h b/device/fido/cable/fido_cable_discovery.h
index 559894f..1ea2ffd3 100644
--- a/device/fido/cable/fido_cable_discovery.h
+++ b/device/fido/cable/fido_cable_discovery.h
@@ -53,13 +53,29 @@
     Result();
     Result(const CableDiscoveryData& in_discovery_data,
            const CableNonce& in_nonce,
-           const CableEidArray& in_eid);
+           const CableEidArray& in_eid,
+           base::Optional<int> ticks_back);
     Result(const Result&);
     ~Result();
 
     CableDiscoveryData discovery_data;
     CableNonce nonce;
     CableEidArray eid;
+    // ticks_back is either |base::nullopt|, if the Result is from established
+    // discovery pairings, or else contains the number of QR ticks back in time
+    // against which the match was found.
+    base::Optional<int> ticks_back;
+  };
+
+  // ObservedDeviceData contains potential EIDs observed from a BLE device. This
+  // information is kept in order to de-duplicate device-log entries and make
+  // debugging easier.
+  struct ObservedDeviceData {
+    ObservedDeviceData();
+    ~ObservedDeviceData();
+
+    base::Optional<CableEidArray> service_data;
+    std::vector<CableEidArray> uuids;
   };
 
   FRIEND_TEST_ALL_PREFIXES(FidoCableDiscoveryTest,
@@ -106,12 +122,15 @@
 
   base::Optional<Result> GetCableDiscoveryData(
       const BluetoothDevice* device) const;
-  base::Optional<Result> GetCableDiscoveryDataFromServiceData(
-      const BluetoothDevice* device) const;
-  base::Optional<Result> GetCableDiscoveryDataFromServiceUUIDs(
-      const BluetoothDevice* device) const;
+  static base::Optional<CableEidArray> MaybeGetEidFromServiceData(
+      const BluetoothDevice* device);
+  static std::vector<CableEidArray> GetUUIDs(const BluetoothDevice* device);
   base::Optional<Result> GetCableDiscoveryDataFromAuthenticatorEid(
       CableEidArray authenticator_eid) const;
+  // ResultDebugString returns a containing a hex dump of |eid| and a
+  // description of |result|, if present.
+  static std::string ResultDebugString(const CableEidArray& eid,
+                                       const base::Optional<Result>& result);
 
   std::vector<CableDiscoveryData> discovery_data_;
   // active_authenticator_eids_ contains authenticator EIDs for which a
@@ -133,6 +152,12 @@
   base::Optional<
       base::RepeatingCallback<void(std::unique_ptr<CableDiscoveryData>)>>
       pairing_callback_;
+
+  // observed_devices_ caches the information from observed caBLE devices so
+  // that the device-log isn't spammed.
+  mutable base::flat_map<std::string, std::unique_ptr<ObservedDeviceData>>
+      observed_devices_;
+
   base::WeakPtrFactory<FidoCableDiscovery> weak_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(FidoCableDiscovery);
diff --git a/device/fido/cable/fido_cable_handshake_handler.cc b/device/fido/cable/fido_cable_handshake_handler.cc
index c1b3f6a..c7c26ea 100644
--- a/device/fido/cable/fido_cable_handshake_handler.cc
+++ b/device/fido/cable/fido_cable_handshake_handler.cc
@@ -211,7 +211,7 @@
     base::span<const uint8_t> ikm) {
   uint8_t output[32 * 2];
   HKDF(output, sizeof(output), EVP_sha256(), ikm.data(), ikm.size(), ck.data(),
-       ck.size(), /*salt=*/nullptr, 0);
+       ck.size(), /*info=*/nullptr, 0);
 
   std::array<uint8_t, 32> a, b;
   memcpy(a.data(), &output[0], 32);
@@ -230,7 +230,7 @@
 HKDF3(base::span<const uint8_t, 32> ck, base::span<const uint8_t> ikm) {
   uint8_t output[32 * 3];
   HKDF(output, sizeof(output), EVP_sha256(), ikm.data(), ikm.size(), ck.data(),
-       ck.size(), /*salt=*/nullptr, 0);
+       ck.size(), /*info=*/nullptr, 0);
 
   std::array<uint8_t, 32> a, b, c;
   memcpy(a.data(), &output[0], 32);
diff --git a/device/fido/fido_constants.cc b/device/fido/fido_constants.cc
index c07c373..893cb62 100644
--- a/device/fido/fido_constants.cc
+++ b/device/fido/fido_constants.cc
@@ -32,7 +32,7 @@
 const char kBioEnrollmentMapKey[] = "bioEnroll";
 const char kBioEnrollmentPreviewMapKey[] = "userVerificationMgmtPreview";
 
-const base::TimeDelta kDeviceTimeout = base::TimeDelta::FromSeconds(10);
+const base::TimeDelta kDeviceTimeout = base::TimeDelta::FromSeconds(15);
 const base::TimeDelta kU2fRetryDelay = base::TimeDelta::FromMilliseconds(200);
 
 const char kFormatKey[] = "fmt";
diff --git a/docs/gpu/gpu_testing.md b/docs/gpu/gpu_testing.md
index 000bf9a..f00c82eb 100644
--- a/docs/gpu/gpu_testing.md
+++ b/docs/gpu/gpu_testing.md
@@ -522,9 +522,36 @@
 
 [pixel wrangling triage]: pixel_wrangling.md#How-to-Keep-the-Bots-Green
 
+If you are adding a new pixel test, it is beneficial to set the
+`grace_period_end` argument in the test's definition. This will allow the test
+to run for a period without actually failing on the waterfall bots, giving you
+some time to triage any additional images that show up on them. This helps
+prevent new tests from making the bots red because they're producing slightly
+different but valid images from the ones triaged while the CL was in review.
+Example:
+
+```
+from datetime import date
+
+...
+
+PixelTestPage(
+  'foo_pixel_test.html',
+  ...
+  grace_period_end=date(2020, 1, 1)
+)
+```
+
+You should typically set the grace period to end 1-2 days after the the CL will
+land.
+
 Once your CL passes the CQ, you should be mostly good to go, although you should
 keep an eye on the waterfall bots for a short period after your CL lands in case
 any configurations not covered by the CQ need to have images approved, as well.
+All untriaged images for your test can be found by substituting your test name
+into:
+
+`https://chrome-gpu-gold.skia.org/search?query=name%3D<test name>`
 
 ## Stamping out Flakiness
 
diff --git a/extensions/browser/content_hash_fetcher_unittest.cc b/extensions/browser/content_hash_fetcher_unittest.cc
index c44e764..527a43b 100644
--- a/extensions/browser/content_hash_fetcher_unittest.cc
+++ b/extensions/browser/content_hash_fetcher_unittest.cc
@@ -176,7 +176,7 @@
 
   void RegisterInterceptionWithFailure(const GURL& url, int net_error) {
     test_url_loader_factory_.AddResponse(
-        GURL(url), network::ResourceResponseHead(), std::string(),
+        GURL(url), network::mojom::URLResponseHead::New(), std::string(),
         network::URLLoaderCompletionStatus(net_error));
   }
 
diff --git a/google_apis/gaia/oauth2_access_token_fetcher_impl_unittest.cc b/google_apis/gaia/oauth2_access_token_fetcher_impl_unittest.cc
index 4a9ca46..4d1ce69 100644
--- a/google_apis/gaia/oauth2_access_token_fetcher_impl_unittest.cc
+++ b/google_apis/gaia/oauth2_access_token_fetcher_impl_unittest.cc
@@ -91,7 +91,7 @@
       url_loader_factory_.AddResponse(url.spec(), body, http_response_code);
     } else {
       url_loader_factory_.AddResponse(
-          url, network::ResourceResponseHead(), body,
+          url, network::mojom::URLResponseHead::New(), body,
           network::URLLoaderCompletionStatus(net_error_code));
     }
 
@@ -103,8 +103,7 @@
     GURL url(GaiaUrls::GetInstance()->oauth2_token_url());
     url_loader_factory_.AddResponse(
         url,
-        network::CreateResourceResponseHead(
-            net::HTTP_PROXY_AUTHENTICATION_REQUIRED),
+        network::CreateURLResponseHead(net::HTTP_PROXY_AUTHENTICATION_REQUIRED),
         std::string(),
         network::URLLoaderCompletionStatus(net::ERR_TUNNEL_CONNECTION_FAILED),
         network::TestURLLoaderFactory::Redirects(),
diff --git a/google_apis/gaia/oauth2_api_call_flow_unittest.cc b/google_apis/gaia/oauth2_api_call_flow_unittest.cc
index 8534328..e1a50374 100644
--- a/google_apis/gaia/oauth2_api_call_flow_unittest.cc
+++ b/google_apis/gaia/oauth2_api_call_flow_unittest.cc
@@ -86,10 +86,10 @@
                       const std::string& body) {
     net::Error error = fetch_succeeds ? net::OK : net::ERR_FAILED;
 
-    network::ResourceResponseHead http_head =
-        network::CreateResourceResponseHead(response_code);
+    auto http_head = network::CreateURLResponseHead(response_code);
     test_url_loader_factory_.AddResponse(
-        url, http_head, body, network::URLLoaderCompletionStatus(error));
+        url, std::move(http_head), body,
+        network::URLLoaderCompletionStatus(error));
   }
 
   void SetupApiCall(bool succeeds, net::HttpStatusCode status) {
diff --git a/google_apis/gaia/oauth2_mint_token_flow_unittest.cc b/google_apis/gaia/oauth2_mint_token_flow_unittest.cc
index 16231457..ca05a90 100644
--- a/google_apis/gaia/oauth2_mint_token_flow_unittest.cc
+++ b/google_apis/gaia/oauth2_mint_token_flow_unittest.cc
@@ -16,7 +16,6 @@
 #include "google_apis/gaia/google_service_auth_error.h"
 #include "google_apis/gaia/oauth2_access_token_fetcher.h"
 #include "net/base/net_errors.h"
-#include "services/network/public/cpp/resource_response.h"
 #include "services/network/public/mojom/url_response_head.mojom.h"
 #include "services/network/test/test_utils.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -299,7 +298,7 @@
 
 TEST_F(OAuth2MintTokenFlowTest, ProcessApiCallSuccess) {
   network::mojom::URLResponseHeadPtr head_200 =
-      network::CreateResourceResponseHead(net::HTTP_OK);
+      network::CreateURLResponseHead(net::HTTP_OK);
 
   {  // No body.
     CreateFlow(OAuth2MintTokenFlow::MODE_MINT_TOKEN_NO_FORCE);
diff --git a/google_apis/gcm/engine/gcm_request_test_base.cc b/google_apis/gcm/engine/gcm_request_test_base.cc
index 2bd18a59..ddd869b 100644
--- a/google_apis/gcm/engine/gcm_request_test_base.cc
+++ b/google_apis/gcm/engine/gcm_request_test_base.cc
@@ -83,7 +83,7 @@
   OnAboutToCompleteFetch();
   EXPECT_TRUE(test_url_loader_factory_.SimulateResponseForPendingRequest(
       GURL(url), network::URLLoaderCompletionStatus(net_error_code),
-      network::CreateResourceResponseHead(status_code), response_body));
+      network::CreateURLResponseHead(status_code), response_body));
 }
 
 const net::HttpRequestHeaders* GCMRequestTestBase::GetExtraHeadersForURL(
diff --git a/gpu/command_buffer/service/external_vk_image_backing.cc b/gpu/command_buffer/service/external_vk_image_backing.cc
index 737c8739..d31121f 100644
--- a/gpu/command_buffer/service/external_vk_image_backing.cc
+++ b/gpu/command_buffer/service/external_vk_image_backing.cc
@@ -14,11 +14,13 @@
 #include "components/viz/common/resources/resource_sizes.h"
 #include "gpu/command_buffer/service/external_vk_image_gl_representation.h"
 #include "gpu/command_buffer/service/external_vk_image_skia_representation.h"
+#include "gpu/command_buffer/service/skia_utils.h"
 #include "gpu/ipc/common/vulkan_ycbcr_info.h"
 #include "gpu/vulkan/vulkan_command_buffer.h"
 #include "gpu/vulkan/vulkan_command_pool.h"
 #include "gpu/vulkan/vulkan_fence_helper.h"
 #include "gpu/vulkan/vulkan_function_pointers.h"
+#include "gpu/vulkan/vulkan_util.h"
 #include "ui/gfx/buffer_format_util.h"
 #include "ui/gl/buildflags.h"
 #include "ui/gl/gl_context.h"
@@ -39,26 +41,13 @@
 
 namespace {
 
-GrVkImageInfo CreateGrVkImageInfo(VkImage image,
-                                  VkFormat vk_format,
-                                  VkDeviceMemory memory,
-                                  size_t memory_size,
-                                  bool use_protected_memory,
-                                  base::Optional<VulkanYCbCrInfo> ycbcr_info) {
-  GrVkYcbcrConversionInfo gr_ycbcr_info{};
-  if (ycbcr_info) {
-    gr_ycbcr_info = GrVkYcbcrConversionInfo(
-        static_cast<VkFormat>(ycbcr_info->image_format),
-        ycbcr_info->external_format,
-        static_cast<VkSamplerYcbcrModelConversion>(
-            ycbcr_info->suggested_ycbcr_model),
-        static_cast<VkSamplerYcbcrRange>(ycbcr_info->suggested_ycbcr_range),
-        static_cast<VkChromaLocation>(ycbcr_info->suggested_xchroma_offset),
-        static_cast<VkChromaLocation>(ycbcr_info->suggested_ychroma_offset),
-        static_cast<VkFilter>(VK_FILTER_LINEAR),
-        /*forceExplicitReconstruction=*/false,
-        static_cast<VkFormatFeatureFlags>(ycbcr_info->format_features));
-  }
+GrVkImageInfo CreateGrVkImageInfo(
+    VkImage image,
+    VkFormat vk_format,
+    VkDeviceMemory memory,
+    size_t memory_size,
+    bool use_protected_memory,
+    const GrVkYcbcrConversionInfo& gr_ycbcr_info) {
   GrVkAlloc alloc(memory, 0 /* offset */, memory_size, 0 /* flags */);
   return GrVkImageInfo(
       image, alloc, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_LAYOUT_UNDEFINED,
@@ -179,8 +168,7 @@
     const gfx::ColorSpace& color_space,
     uint32_t usage,
     base::span<const uint8_t> pixel_data,
-    bool using_gmb,
-    base::Optional<VulkanYCbCrInfo> ycbcr_info) {
+    bool using_gmb) {
   VkDevice device =
       context_state->vk_context_provider()->GetDeviceQueue()->GetVulkanDevice();
   VkFormat vk_format = ToVkFormat(format);
@@ -246,7 +234,7 @@
 
   auto backing = base::WrapUnique(new ExternalVkImageBacking(
       mailbox, format, size, color_space, usage, context_state, image, memory,
-      requirements.size, vk_format, command_pool, ycbcr_info,
+      requirements.size, vk_format, command_pool, GrVkYcbcrConversionInfo(),
       GetDawnFormat(format), mem_alloc_info.memoryTypeIndex));
 
   if (!pixel_data.empty()) {
@@ -286,7 +274,7 @@
     VkImageCreateInfo vk_image_info = {VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO};
     VkDeviceMemory vk_device_memory = VK_NULL_HANDLE;
     VkDeviceSize memory_size = 0;
-    base::Optional<gpu::VulkanYCbCrInfo> ycbcr_info;
+    base::Optional<VulkanYCbCrInfo> ycbcr_info;
 
     if (!vulkan_implementation->CreateImageFromGpuMemoryHandle(
             vk_device, std::move(handle), size, &vk_image, &vk_image_info,
@@ -303,10 +291,16 @@
       return nullptr;
     }
 
+    GrVkYcbcrConversionInfo gr_ycbcr_info =
+        CreateGrVkYcbcrConversionInfo(context_state->vk_context_provider()
+                                          ->GetDeviceQueue()
+                                          ->GetVulkanPhysicalDevice(),
+                                      vk_image_info.tiling, ycbcr_info);
+
     return base::WrapUnique(new ExternalVkImageBacking(
         mailbox, resource_format, size, color_space, usage, context_state,
         vk_image, vk_device_memory, memory_size, vk_image_info.format,
-        command_pool, ycbcr_info, GetDawnFormat(resource_format), {}));
+        command_pool, gr_ycbcr_info, GetDawnFormat(resource_format), {}));
   }
 
   if (gfx::NumberOfPlanesForLinearBufferFormat(buffer_format) != 1) {
@@ -406,7 +400,7 @@
     size_t memory_size,
     VkFormat vk_format,
     VulkanCommandPool* command_pool,
-    base::Optional<VulkanYCbCrInfo> ycbcr_info,
+    const GrVkYcbcrConversionInfo& ycbcr_info,
     base::Optional<DawnTextureFormat> dawn_format,
     base::Optional<uint32_t> memory_type_index)
     : SharedImageBacking(mailbox,
diff --git a/gpu/command_buffer/service/external_vk_image_backing.h b/gpu/command_buffer/service/external_vk_image_backing.h
index 1ee71f9..7e89c89 100644
--- a/gpu/command_buffer/service/external_vk_image_backing.h
+++ b/gpu/command_buffer/service/external_vk_image_backing.h
@@ -16,7 +16,6 @@
 #include "gpu/command_buffer/service/shared_context_state.h"
 #include "gpu/command_buffer/service/shared_image_backing.h"
 #include "gpu/command_buffer/service/texture_manager.h"
-#include "gpu/ipc/common/vulkan_ycbcr_info.h"
 #include "gpu/vulkan/semaphore_handle.h"
 #include "gpu/vulkan/vulkan_device_queue.h"
 #include "ui/gfx/gpu_memory_buffer.h"
@@ -36,8 +35,7 @@
       const gfx::ColorSpace& color_space,
       uint32_t usage,
       base::span<const uint8_t> pixel_data,
-      bool using_gmb = false,
-      base::Optional<VulkanYCbCrInfo> ycbcr_info = base::nullopt);
+      bool using_gmb = false);
 
   static std::unique_ptr<ExternalVkImageBacking> CreateFromGMB(
       SharedContextState* context_state,
@@ -129,7 +127,7 @@
                          size_t memory_size,
                          VkFormat vk_format,
                          VulkanCommandPool* command_pool,
-                         base::Optional<VulkanYCbCrInfo> ycbcr_info,
+                         const GrVkYcbcrConversionInfo& ycbcr_info,
                          base::Optional<DawnTextureFormat> dawn_format,
                          base::Optional<uint32_t> memory_type_index);
 
diff --git a/gpu/command_buffer/service/skia_utils.cc b/gpu/command_buffer/service/skia_utils.cc
index a2b41ae..b4f9d29 100644
--- a/gpu/command_buffer/service/skia_utils.cc
+++ b/gpu/command_buffer/service/skia_utils.cc
@@ -19,6 +19,7 @@
 #if BUILDFLAG(ENABLE_VULKAN)
 #include "gpu/vulkan/vulkan_device_queue.h"
 #include "gpu/vulkan/vulkan_fence_helper.h"
+#include "gpu/vulkan/vulkan_function_pointers.h"
 #endif
 
 namespace gpu {
@@ -131,4 +132,45 @@
 #endif
 }
 
+#if BUILDFLAG(ENABLE_VULKAN)
+
+GrVkYcbcrConversionInfo CreateGrVkYcbcrConversionInfo(
+    VkPhysicalDevice physical_device,
+    VkImageTiling tiling,
+    const base::Optional<VulkanYCbCrInfo>& ycbcr_info) {
+  if (!ycbcr_info)
+    return GrVkYcbcrConversionInfo();
+
+  VkFormat vk_format = static_cast<VkFormat>(ycbcr_info->image_format);
+  VkFormatFeatureFlags format_features =
+      static_cast<VkFormatFeatureFlags>(ycbcr_info->format_features);
+
+  // |format_features| is expected to be set for external images. For regular
+  // (non-external) images it may be set to 0. In that case we need to get the
+  // value from Vulkan.
+  if (format_features == 0) {
+    DCHECK_NE(vk_format, 0);
+    VkFormatProperties format_props = {};
+
+    // vkGetPhysicalDeviceFormatProperties() is safe to call on any thread.
+    vkGetPhysicalDeviceFormatProperties(physical_device, vk_format,
+                                        &format_props);
+    format_features = (tiling == VK_IMAGE_TILING_LINEAR)
+                          ? format_props.linearTilingFeatures
+                          : format_props.optimalTilingFeatures;
+  }
+
+  return GrVkYcbcrConversionInfo(
+      vk_format, ycbcr_info->external_format,
+      static_cast<VkSamplerYcbcrModelConversion>(
+          ycbcr_info->suggested_ycbcr_model),
+      static_cast<VkSamplerYcbcrRange>(ycbcr_info->suggested_ycbcr_range),
+      static_cast<VkChromaLocation>(ycbcr_info->suggested_xchroma_offset),
+      static_cast<VkChromaLocation>(ycbcr_info->suggested_ychroma_offset),
+      static_cast<VkFilter>(VK_FILTER_LINEAR),
+      /*forceExplicitReconstruction=*/false, format_features);
+}
+
+#endif  // BUILDFLAG(ENABLE_VULKAN)
+
 }  // namespace gpu
diff --git a/gpu/command_buffer/service/skia_utils.h b/gpu/command_buffer/service/skia_utils.h
index 9fe069c..7968e96 100644
--- a/gpu/command_buffer/service/skia_utils.h
+++ b/gpu/command_buffer/service/skia_utils.h
@@ -6,10 +6,14 @@
 #define GPU_COMMAND_BUFFER_SERVICE_SKIA_UTILS_H_
 
 #include "base/callback_forward.h"
+#include "base/optional.h"
 #include "components/viz/common/resources/resource_format.h"
 #include "gpu/gpu_gles2_export.h"
+#include "gpu/ipc/common/vulkan_ycbcr_info.h"
+#include "gpu/vulkan/buildflags.h"
 #include "third_party/skia/include/core/SkSurface.h"
 #include "third_party/skia/include/gpu/GrTypes.h"
+#include "third_party/skia/include/gpu/vk/GrVkTypes.h"
 
 // Forwardly declare a few GL types to avoid including GL header files.
 typedef int GLint;
@@ -62,6 +66,14 @@
 GPU_GLES2_EXPORT void DeleteGrBackendTexture(
     SharedContextState* context_state,
     GrBackendTexture* backend_textures);
+
+#if BUILDFLAG(ENABLE_VULKAN)
+GPU_GLES2_EXPORT GrVkYcbcrConversionInfo CreateGrVkYcbcrConversionInfo(
+    VkPhysicalDevice physical_device,
+    VkImageTiling tiling,
+    const base::Optional<VulkanYCbCrInfo>& ycbcr_info);
+#endif  // BUILDFLAG(ENABLE_VULKAN)
+
 }  // namespace gpu
 
 #endif  // GPU_COMMAND_BUFFER_SERVICE_SKIA_UTILS_H_
diff --git a/gpu/ipc/common/vulkan_ycbcr_info.cc b/gpu/ipc/common/vulkan_ycbcr_info.cc
index e6d7fab..50c15275 100644
--- a/gpu/ipc/common/vulkan_ycbcr_info.cc
+++ b/gpu/ipc/common/vulkan_ycbcr_info.cc
@@ -26,6 +26,9 @@
       format_features(format_features) {
   // One and only one of the format fields must be non-zero.
   DCHECK((image_format == 0) ^ (external_format == 0));
+
+  // |format_features| must be set for external images.
+  DCHECK(external_format == 0 || format_features != 0);
 }
 
 }  // namespace gpu
diff --git a/gpu/ipc/common/vulkan_ycbcr_info.h b/gpu/ipc/common/vulkan_ycbcr_info.h
index 91fa0348..2c2612a4 100644
--- a/gpu/ipc/common/vulkan_ycbcr_info.h
+++ b/gpu/ipc/common/vulkan_ycbcr_info.h
@@ -52,8 +52,9 @@
   uint32_t suggested_ychroma_offset;
 
   // Describes the capabilities of the format when used with an image bound to
-  // memory imported from buffer. Corresponds to vulkan type:
-  // VkFormatFeatureFlags.
+  // memory imported from buffer. Must be set when for external-format image
+  // created from the Android hardware buffer. For regular (not external) images
+  // it can be set 0. Corresponds to Vulkan type: VkFormatFeatureFlags.
   uint32_t format_features;
 };
 
diff --git a/gpu/vulkan/generate_bindings.py b/gpu/vulkan/generate_bindings.py
index 0d7a589..c9681c0 100755
--- a/gpu/vulkan/generate_bindings.py
+++ b/gpu/vulkan/generate_bindings.py
@@ -34,6 +34,7 @@
       'vkEnumeratePhysicalDevices',
       'vkGetDeviceProcAddr',
       'vkGetPhysicalDeviceFeatures',
+      'vkGetPhysicalDeviceFormatProperties',
       'vkGetPhysicalDeviceMemoryProperties',
       'vkGetPhysicalDeviceProperties',
       'vkGetPhysicalDeviceQueueFamilyProperties',
diff --git a/gpu/vulkan/vulkan_function_pointers.cc b/gpu/vulkan/vulkan_function_pointers.cc
index ba7e5fc..9c3cea9 100644
--- a/gpu/vulkan/vulkan_function_pointers.cc
+++ b/gpu/vulkan/vulkan_function_pointers.cc
@@ -124,6 +124,16 @@
     return false;
   }
 
+  vkGetPhysicalDeviceFormatPropertiesFn =
+      reinterpret_cast<PFN_vkGetPhysicalDeviceFormatProperties>(
+          vkGetInstanceProcAddrFn(vk_instance,
+                                  "vkGetPhysicalDeviceFormatProperties"));
+  if (!vkGetPhysicalDeviceFormatPropertiesFn) {
+    DLOG(WARNING) << "Failed to bind vulkan entrypoint: "
+                  << "vkGetPhysicalDeviceFormatProperties";
+    return false;
+  }
+
   vkGetPhysicalDeviceMemoryPropertiesFn =
       reinterpret_cast<PFN_vkGetPhysicalDeviceMemoryProperties>(
           vkGetInstanceProcAddrFn(vk_instance,
diff --git a/gpu/vulkan/vulkan_function_pointers.h b/gpu/vulkan/vulkan_function_pointers.h
index 3d73440..78295b6 100644
--- a/gpu/vulkan/vulkan_function_pointers.h
+++ b/gpu/vulkan/vulkan_function_pointers.h
@@ -78,6 +78,8 @@
   PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevicesFn = nullptr;
   PFN_vkGetDeviceProcAddr vkGetDeviceProcAddrFn = nullptr;
   PFN_vkGetPhysicalDeviceFeatures vkGetPhysicalDeviceFeaturesFn = nullptr;
+  PFN_vkGetPhysicalDeviceFormatProperties
+      vkGetPhysicalDeviceFormatPropertiesFn = nullptr;
   PFN_vkGetPhysicalDeviceMemoryProperties
       vkGetPhysicalDeviceMemoryPropertiesFn = nullptr;
   PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDevicePropertiesFn = nullptr;
@@ -234,6 +236,8 @@
   gpu::GetVulkanFunctionPointers()->vkGetDeviceProcAddrFn
 #define vkGetPhysicalDeviceFeatures \
   gpu::GetVulkanFunctionPointers()->vkGetPhysicalDeviceFeaturesFn
+#define vkGetPhysicalDeviceFormatProperties \
+  gpu::GetVulkanFunctionPointers()->vkGetPhysicalDeviceFormatPropertiesFn
 #define vkGetPhysicalDeviceMemoryProperties \
   gpu::GetVulkanFunctionPointers()->vkGetPhysicalDeviceMemoryPropertiesFn
 #define vkGetPhysicalDeviceProperties \
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg
index da421e2..f124b900 100644
--- a/infra/config/cr-buildbucket.cfg
+++ b/infra/config/cr-buildbucket.cfg
@@ -7,22 +7,6 @@
 # Please keep this list sorted by bucket name.
 
 acl_sets {
-  name: "waterfall"
-  acls {
-    role: READER
-    group: "all"
-  }
-  acls {
-    role: SCHEDULER
-    identity: "luci-scheduler@appspot.gserviceaccount.com"
-  }
-  acls {
-    role: WRITER
-    group: "service-account-chromium-master"
-  }
-}
-
-acl_sets {
   # This is pure-LUCI CI w/o buildbot.
   name: "ci"
   acls {
@@ -951,8 +935,6 @@
 builder_mixins {
   name: "findit"
   mixins: "goma-many-jobs-for-ci"
-  # This category is meant for Findit to trigger tryjobs on.
-  category: "Chromium Variable"
   recipe {
     name: "findit/chromium/compile"
   }
@@ -3859,7 +3841,6 @@
   swarming {
     hostname: "chromium-swarm.appspot.com"
     builder_defaults {
-      category: "Chromium Variable"
       dimensions: "pool:luci.chromium.findit"
       service_account: "findit-builder@chops-service-accounts.iam.gserviceaccount.com"
       execution_timeout_secs: 28800  # 8h
@@ -3910,77 +3891,8 @@
 }
 
 buckets {
-  name: "master.chromium.android.fyi"
-  acl_sets: "waterfall"
-}
-
-buckets {
-  name: "master.chromium.perf"
-  acl_sets: "waterfall"
-}
-
-buckets {
-  name: "master.chromium.perf.fyi"
-  acl_sets: "waterfall"
-}
-
-# Defining blink build bucket in chromium/src repo because
-# blink will merge to chromium/src.
-# Also git admins are reluctant to create infra/config branches
-# in svn-based git repos (crbug.com/513580).
-buckets {
-  name: "master.tryserver.blink"
-  acl_sets: "tryserver"
-}
-
-buckets {
-  name: "master.tryserver.chromium.android"
-  acl_sets: "tryserver"
-}
-
-buckets {
-  name: "master.tryserver.chromium.chromiumos"
-  acl_sets: "tryserver"
-}
-
-buckets {
-  name: "master.tryserver.chromium.gpu"
-  acl_sets: "tryserver"
-}
-
-buckets {
-  name: "master.tryserver.chromium.linux"
-  acl_sets: "tryserver"
-}
-
-buckets {
-  name: "master.tryserver.chromium.mac"
-  acl_sets: "tryserver"
-}
-
-buckets {
-  name: "master.tryserver.chromium.perf"
-  acl_sets: "tryserver"
-  acls {
-    role: SCHEDULER
-    group: "service-account-chromium-bisect"
-  }
-  acls {
-    role: SCHEDULER
-    group: "service-account-chromeperf"
-  }
-}
-
-buckets {
-  name: "master.tryserver.chromium.win"
-  acl_sets: "tryserver"
-}
-
-buckets {
   name: "try"
 
-  # NOTE: these ACLs should be kept in sync with those in the other
-  # "master.tryserver.chromium.*" buckets.
   acl_sets: "tryserver"
 
   swarming {
@@ -3988,7 +3900,6 @@
     task_template_canary_percentage { value: 5 }
 
     builder_defaults {
-      category: "Chromium CQ"
       dimensions: "cores:8"
       dimensions: "cpu:x86-64"
       service_account: "chromium-try-builder@chops-service-accounts.iam.gserviceaccount.com"
@@ -4046,14 +3957,6 @@
       name: "android-cronet-arm-dbg"
     }
     builders {
-      name: "android-kitkat-arm-coverage-rel"
-      mixins: "android-try"
-      mixins: "java-coverage"
-      mixins: "goma-j150"
-      mixins: "builderless"
-      mixins: "linux-xenial"
-    }
-    builders {
       name: "android-kitkat-arm-rel"
       mixins: "android-try"
       mixins: "goma-rbe-prod-j150"
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg
index 8df6b07..dd57fb7 100644
--- a/infra/config/luci-milo.cfg
+++ b/infra/config/luci-milo.cfg
@@ -660,19 +660,16 @@
     short_name: "win"
   }
   builders {
-    name: "buildbot/chromium.memory/win-asan"
     name: "buildbucket/luci.chromium.ci/win-asan"
     category: "chromium.memory|win"
     short_name: "asn"
   }
   builders {
-    name: "buildbot/chromium.memory/Mac ASan 64 Builder"
     name: "buildbucket/luci.chromium.ci/Mac ASan 64 Builder"
     category: "chromium.memory|mac"
     short_name: "bld"
   }
   builders {
-    name: "buildbot/chromium.memory/Mac ASan 64 Tests (1)"
     name: "buildbucket/luci.chromium.ci/Mac ASan 64 Tests (1)"
     category: "chromium.memory|mac"
     short_name: "tst"
@@ -703,13 +700,11 @@
     short_name: "sbx"
   }
   builders {
-    name: "buildbot/chromium.memory/Linux MSan Builder"
     name: "buildbucket/luci.chromium.ci/Linux MSan Builder"
     category: "chromium.memory|linux|msan"
     short_name: "bld"
   }
   builders {
-    name: "buildbot/chromium.memory/Linux MSan Tests"
     name: "buildbucket/luci.chromium.ci/Linux MSan Tests"
     category: "chromium.memory|linux|msan"
     short_name: "tst"
@@ -730,25 +725,21 @@
     short_name: "lk"
   }
   builders {
-    name: "buildbot/chromium.memory/Linux Chromium OS ASan LSan Builder"
     name: "buildbucket/luci.chromium.ci/Linux Chromium OS ASan LSan Builder"
     category: "chromium.memory|cros|asan"
     short_name: "bld"
   }
   builders {
-    name: "buildbot/chromium.memory/Linux Chromium OS ASan LSan Tests (1)"
     name: "buildbucket/luci.chromium.ci/Linux Chromium OS ASan LSan Tests (1)"
     category: "chromium.memory|cros|asan"
     short_name: "tst"
   }
   builders {
-    name: "buildbot/chromium.memory/Linux ChromiumOS MSan Builder"
     name: "buildbucket/luci.chromium.ci/Linux ChromiumOS MSan Builder"
     category: "chromium.memory|cros|msan"
     short_name: "bld"
   }
   builders {
-    name: "buildbot/chromium.memory/Linux ChromiumOS MSan Tests"
     name: "buildbucket/luci.chromium.ci/Linux ChromiumOS MSan Tests"
     category: "chromium.memory|cros|msan"
     short_name: "tst"
@@ -759,13 +750,11 @@
     short_name: "asn"
   }
   builders {
-    name: "buildbot/chromium.memory/Android CFI"
     name: "buildbucket/luci.chromium.ci/Android CFI"
     category: "chromium.memory|cfi"
     short_name: "and"
   }
   builders {
-    name: "buildbot/chromium.memory/Linux CFI"
     name: "buildbucket/luci.chromium.ci/Linux CFI"
     category: "chromium.memory|cfi"
     short_name: "lnx"
@@ -1085,19 +1074,16 @@
   refs: "refs/heads/master"
   manifest_name: "REVISION"
   builders {
-    name: "buildbot/chromium.memory/win-asan"
     name: "buildbucket/luci.chromium.ci/win-asan"
     category: "win"
     short_name: "asn"
   }
   builders {
-    name: "buildbot/chromium.memory/Mac ASan 64 Builder"
     name: "buildbucket/luci.chromium.ci/Mac ASan 64 Builder"
     category: "mac"
     short_name: "bld"
   }
   builders {
-    name: "buildbot/chromium.memory/Mac ASan 64 Tests (1)"
     name: "buildbucket/luci.chromium.ci/Mac ASan 64 Tests (1)"
     category: "mac"
     short_name: "tst"
@@ -1128,13 +1114,11 @@
     short_name: "sbx"
   }
   builders {
-    name: "buildbot/chromium.memory/Linux MSan Builder"
     name: "buildbucket/luci.chromium.ci/Linux MSan Builder"
     category: "linux|msan"
     short_name: "bld"
   }
   builders {
-    name: "buildbot/chromium.memory/Linux MSan Tests"
     name: "buildbucket/luci.chromium.ci/Linux MSan Tests"
     category: "linux|msan"
     short_name: "tst"
@@ -1155,25 +1139,21 @@
     short_name: "lk"
   }
   builders {
-    name: "buildbot/chromium.memory/Linux Chromium OS ASan LSan Builder"
     name: "buildbucket/luci.chromium.ci/Linux Chromium OS ASan LSan Builder"
     category: "cros|asan"
     short_name: "bld"
   }
   builders {
-    name: "buildbot/chromium.memory/Linux Chromium OS ASan LSan Tests (1)"
     name: "buildbucket/luci.chromium.ci/Linux Chromium OS ASan LSan Tests (1)"
     category: "cros|asan"
     short_name: "tst"
   }
   builders {
-    name: "buildbot/chromium.memory/Linux ChromiumOS MSan Builder"
     name: "buildbucket/luci.chromium.ci/Linux ChromiumOS MSan Builder"
     category: "cros|msan"
     short_name: "bld"
   }
   builders {
-    name: "buildbot/chromium.memory/Linux ChromiumOS MSan Tests"
     name: "buildbucket/luci.chromium.ci/Linux ChromiumOS MSan Tests"
     category: "cros|msan"
     short_name: "tst"
@@ -1184,13 +1164,11 @@
     short_name: "asn"
   }
   builders {
-    name: "buildbot/chromium.memory/Android CFI"
     name: "buildbucket/luci.chromium.ci/Android CFI"
     category: "cfi"
     short_name: "and"
   }
   builders {
-    name: "buildbot/chromium.memory/Linux CFI"
     name: "buildbucket/luci.chromium.ci/Linux CFI"
     category: "cfi"
     short_name: "lnx"
@@ -1362,26 +1340,6 @@
 
 consoles {
   header_id: "chromium"
-  include_experimental_builds: true
-  id: "migration-side-by-side"
-  name: "LUCI CI Migration Comparison Console"
-  repo_url: "https://chromium.googlesource.com/chromium/src"
-  refs: "refs/heads/master"
-  manifest_name: "REVISION"
-  builders {
-    name: "buildbucket/luci.chromium.ci/Cast Android (dbg)"
-    category: "android|cast"
-    short_name: "ci"
-  }
-  builders {
-    name: "buildbot/chromium.android/Cast Android (dbg)"
-    category: "android|cast"
-    short_name: "bb"
-  }
-}
-
-consoles {
-  header_id: "chromium"
   id: "chromium"
   name: "chromium"
   repo_url: "https://chromium.googlesource.com/chromium/src"
@@ -1610,7 +1568,6 @@
     short_name: "M"
   }
   builders {
-    name: "buildbot/chromium.android/Cast Android (dbg)"
     name: "buildbucket/luci.chromium.ci/Cast Android (dbg)"
     category: "on_cq"
     short_name: "cst"
@@ -1733,7 +1690,6 @@
     short_name: "a64"
   }
   builders {
-    name: "buildbot/chromium.clang/ToTAndroidASan"
     name: "buildbucket/luci.chromium.ci/ToTAndroidASan"
     category: "ToT Android"
     short_name: "asn"
@@ -2488,21 +2444,6 @@
 
 consoles {
   header_id: "chromium"
-  id: "chromium.gatekeeper"
-  name: "chromium.gatekeeper"
-  repo_url: "https://chromium.googlesource.com/chromium/src"
-  refs: "refs/heads/master"
-  manifest_name: "REVISION"
-  builders {
-    name: "buildbot/chromium.gatekeeper/Chromium Gatekeeper"
-  }
-  builders {
-    name: "buildbot/chromium.gatekeeper/Chromium Gatekeeper Failure"
-  }
-}
-
-consoles {
-  header_id: "chromium"
   id: "chromium.goma"
   name: "chromium.goma"
   repo_url: "https://chromium.googlesource.com/chromium/src"
@@ -4352,9 +4293,6 @@
   refs: "refs/heads/master"
   manifest_name: "REVISION"
   builders {
-    name: "buildbot/tryserver.chromium.android/android_archive_rel_ng"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/android_archive_rel_ng"
   }
   builders {
@@ -4364,9 +4302,6 @@
     name: "buildbucket/luci.chromium.try/android_blink_rel"
   }
   builders {
-    name: "buildbot/tryserver.chromium.android/android_cfi_rel_ng"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/android_cfi_rel_ng"
   }
   builders {
@@ -4376,18 +4311,12 @@
     name: "buildbucket/luci.chromium.try/android_compile_dbg"
   }
   builders {
-    name: "buildbot/tryserver.chromium.android/android_compile_rel"
-  }
-  builders {
-    name: "buildbot/tryserver.chromium.android/android_compile_x64_dbg"
+    name: "buildbucket/luci.chromium.try/android_compile_rel"
   }
   builders {
     name: "buildbucket/luci.chromium.try/android_compile_x64_dbg"
   }
   builders {
-    name: "buildbot/tryserver.chromium.android/android_compile_x86_dbg"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/android_compile_x86_dbg"
   }
   builders {
@@ -4397,10 +4326,7 @@
     name: "buildbucket/luci.chromium.try/android-cronet-arm-dbg"
   }
   builders {
-    name: "buildbot/tryserver.chromium.android/android_cronet_tester"
-  }
-  builders {
-    name: "buildbot/tryserver.chromium.android/android_mojo"
+    name: "buildbucket/luci.chromium.try/android_cronet_tester"
   }
   builders {
     name: "buildbucket/luci.chromium.try/android_mojo"
@@ -4427,9 +4353,6 @@
     name: "buildbucket/luci.chromium.try/cast_shell_android"
   }
   builders {
-    name: "buildbot/tryserver.chromium.android/linux_android_dbg_ng"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/linux_android_dbg_ng"
   }
   builders {
@@ -4832,47 +4755,7 @@
     name: "buildbucket/luci.chromium.try/mac_optional_gpu_tests_rel"
   }
   builders {
-    name: "buildbot/tryserver.chromium.mac/mac_upload_clang"
-  }
-  builder_view_only: true
-}
-
-consoles {
-  header_id: "chromium"
-  id: "tryserver.chromium.perf"
-  name: "tryserver.chromium.perf"
-  repo_url: "https://chromium.googlesource.com/chromium/src"
-  refs: "refs/heads/master"
-  manifest_name: "REVISION"
-  builders {
-    name: "buildbot/tryserver.chromium.perf/Android Compile Perf"
-  }
-  builders {
-    name: "buildbot/tryserver.chromium.perf/Android arm64 Compile Perf"
-  }
-  builders {
-    name: "buildbot/tryserver.chromium.perf/Linux Builder Perf"
-  }
-  builders {
-    name: "buildbot/tryserver.chromium.perf/Mac Builder Perf"
-  }
-  builders {
-    name: "buildbot/tryserver.chromium.perf/Win Builder Perf"
-  }
-  builders {
-    name: "buildbot/tryserver.chromium.perf/Win x64 Builder Perf"
-  }
-  builders {
-    name: "buildbot/tryserver.chromium.perf/linux_fyi_perf_bisect"
-  }
-  builders {
-    name: "buildbot/tryserver.chromium.perf/linux_perf_bisect"
-  }
-  builders {
-    name: "buildbot/tryserver.chromium.perf/linux_perf_bisect_builder"
-  }
-  builders {
-    name: "buildbot/tryserver.chromium.perf/staging_linux_perf_bisect"
+    name: "buildbucket/luci.chromium.try/mac_upload_clang"
   }
   builder_view_only: true
 }
@@ -4982,35 +4865,27 @@
   refs: "refs/heads/master"
   manifest_name: "REVISION"
   builders {
-    name: "buildbot/tryserver.blink/linux-blink-rel"
     name: "buildbucket/luci.chromium.try/linux-blink-rel"
   }
   builders {
-    name: "buildbot/tryserver.blink/mac10.10-blink-rel"
     name: "buildbucket/luci.chromium.try/mac10.10-blink-rel"
   }
   builders {
-    name: "buildbot/tryserver.blink/mac10.11-blink-rel"
     name: "buildbucket/luci.chromium.try/mac10.11-blink-rel"
   }
   builders {
-    name: "buildbot/tryserver.blink/mac10.12-blink-rel"
     name: "buildbucket/luci.chromium.try/mac10.12-blink-rel"
   }
   builders {
-    name: "buildbot/tryserver.blink/mac10.13-blink-rel"
     name: "buildbucket/luci.chromium.try/mac10.13-blink-rel"
   }
   builders {
-    name: "buildbot/tryserver.blink/mac10.13_retina-blink-rel"
     name: "buildbucket/luci.chromium.try/mac10.13_retina-blink-rel"
   }
   builders {
-    name: "buildbot/tryserver.blink/win10-blink-rel"
     name: "buildbucket/luci.chromium.try/win10-blink-rel"
   }
   builders {
-    name: "buildbot/tryserver.blink/win7-blink-rel"
     name: "buildbucket/luci.chromium.try/win7-blink-rel"
   }
   builder_view_only: true
@@ -5082,9 +4957,6 @@
     name: "buildbucket/luci.chromium.try/android-cronet-arm-dbg"
   }
   builders {
-    name: "buildbucket/luci.chromium.try/android-kitkat-arm-coverage-rel"
-  }
-  builders {
     name: "buildbucket/luci.chromium.try/android-kitkat-arm-rel"
   }
   builders {
diff --git a/ios/chrome/browser/omaha/omaha_service_unittest.mm b/ios/chrome/browser/omaha/omaha_service_unittest.mm
index ae7dd32b..d63e8cf6 100644
--- a/ios/chrome/browser/omaha/omaha_service_unittest.mm
+++ b/ios/chrome/browser/omaha/omaha_service_unittest.mm
@@ -333,11 +333,11 @@
   base::Time next_tries_time = service.next_tries_time_;
 
   auto* pending_request = test_url_loader_factory_.GetPendingRequest(0);
-  auto resource_response_head =
-      network::CreateResourceResponseHead(net::HTTP_BAD_REQUEST);
+  auto url_response_head =
+      network::CreateURLResponseHead(net::HTTP_BAD_REQUEST);
   test_url_loader_factory_.SimulateResponseForPendingRequest(
       pending_request->request.url, network::URLLoaderCompletionStatus(net::OK),
-      resource_response_head, std::string());
+      std::move(url_response_head), std::string());
 
   EXPECT_EQ(1, service.number_of_tries_);
   EXPECT_TRUE(service.current_ping_time_.is_null());
diff --git a/ios/chrome/browser/reading_list/url_downloader_unittest.mm b/ios/chrome/browser/reading_list/url_downloader_unittest.mm
index b5f4fdd..3df5af7 100644
--- a/ios/chrome/browser/reading_list/url_downloader_unittest.mm
+++ b/ios/chrome/browser/reading_list/url_downloader_unittest.mm
@@ -224,11 +224,11 @@
   task_environment_.RunUntilIdle();
 
   auto* pending_request = test_url_loader_factory_.GetPendingRequest(0);
-  auto response_info = network::CreateResourceResponseHead(net::HTTP_OK);
-  response_info.mime_type = "application/pdf";
+  auto response_info = network::CreateURLResponseHead(net::HTTP_OK);
+  response_info->mime_type = "application/pdf";
   test_url_loader_factory_.SimulateResponseForPendingRequest(
       pending_request->request.url, network::URLLoaderCompletionStatus(net::OK),
-      response_info, std::string("123456789"));
+      std::move(response_info), std::string("123456789"));
 
   // Wait for all asynchronous tasks to complete.
   task_environment_.RunUntilIdle();
diff --git a/ios/chrome/browser/ui/badges/BUILD.gn b/ios/chrome/browser/ui/badges/BUILD.gn
index 069fe26..a2bca236 100644
--- a/ios/chrome/browser/ui/badges/BUILD.gn
+++ b/ios/chrome/browser/ui/badges/BUILD.gn
@@ -32,7 +32,6 @@
   ]
   deps = [
     ":public",
-    "resources:badge_menu_item_gear",
     "resources:incognito_badge",
     "resources:incognito_small_badge",
     "resources:wrench_badge",
@@ -45,6 +44,7 @@
     "//ios/chrome/browser/ui/elements",
     "//ios/chrome/browser/ui/fullscreen:ui",
     "//ios/chrome/browser/ui/infobars:feature_flags",
+    "//ios/chrome/browser/ui/infobars/resources:infobar_settings_icon",
     "//ios/chrome/browser/ui/list_model",
     "//ios/chrome/browser/ui/util",
     "//ios/chrome/browser/web",
diff --git a/ios/chrome/browser/ui/badges/badge_popup_menu_item.mm b/ios/chrome/browser/ui/badges/badge_popup_menu_item.mm
index 23864cb..3636631e 100644
--- a/ios/chrome/browser/ui/badges/badge_popup_menu_item.mm
+++ b/ios/chrome/browser/ui/badges/badge_popup_menu_item.mm
@@ -146,7 +146,7 @@
 
     _trailingImageView = [[UIImageView alloc]
         initWithImage:
-            [[UIImage imageNamed:@"badge_menu_item_gear"]
+            [[UIImage imageNamed:@"infobar_settings_icon"]
                 imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]];
     _trailingImageView.translatesAutoresizingMaskIntoConstraints = NO;
     _trailingImageView.tintColor = [UIColor colorNamed:kBlueColor];
diff --git a/ios/chrome/browser/ui/badges/resources/BUILD.gn b/ios/chrome/browser/ui/badges/resources/BUILD.gn
index c096c37..e57f829 100644
--- a/ios/chrome/browser/ui/badges/resources/BUILD.gn
+++ b/ios/chrome/browser/ui/badges/resources/BUILD.gn
@@ -27,11 +27,3 @@
     "wrench_badge.imageset/wrench_badge@3x.png",
   ]
 }
-
-imageset("badge_menu_item_gear") {
-  sources = [
-    "badge_menu_item_gear.imageset/Contents.json",
-    "badge_menu_item_gear.imageset/badge_menu_item_gear@2x.png",
-    "badge_menu_item_gear.imageset/badge_menu_item_gear@3x.png",
-  ]
-}
diff --git a/ios/chrome/browser/ui/badges/resources/badge_menu_item_gear.imageset/Contents.json b/ios/chrome/browser/ui/badges/resources/badge_menu_item_gear.imageset/Contents.json
deleted file mode 100644
index d3e35b7..0000000
--- a/ios/chrome/browser/ui/badges/resources/badge_menu_item_gear.imageset/Contents.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
-    "images": [
-        {
-            "idiom": "universal",
-            "scale": "2x",
-            "filename": "badge_menu_item_gear@2x.png"
-        },
-        {
-            "idiom": "universal",
-            "scale": "3x",
-            "filename": "badge_menu_item_gear@3x.png"
-        }
-    ],
-    "info": {
-        "version": 1,
-        "author": "xcode"
-    }
-}
diff --git a/ios/chrome/browser/ui/badges/resources/badge_menu_item_gear.imageset/badge_menu_item_gear@2x.png b/ios/chrome/browser/ui/badges/resources/badge_menu_item_gear.imageset/badge_menu_item_gear@2x.png
deleted file mode 100644
index 36b296c9..0000000
--- a/ios/chrome/browser/ui/badges/resources/badge_menu_item_gear.imageset/badge_menu_item_gear@2x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/badges/resources/badge_menu_item_gear.imageset/badge_menu_item_gear@3x.png b/ios/chrome/browser/ui/badges/resources/badge_menu_item_gear.imageset/badge_menu_item_gear@3x.png
deleted file mode 100644
index 34547e1..0000000
--- a/ios/chrome/browser/ui/badges/resources/badge_menu_item_gear.imageset/badge_menu_item_gear@3x.png
+++ /dev/null
Binary files differ
diff --git a/ios/chrome/browser/ui/omnibox/omnibox_util.mm b/ios/chrome/browser/ui/omnibox/omnibox_util.mm
index eb32628..8b945fc 100644
--- a/ios/chrome/browser/ui/omnibox/omnibox_util.mm
+++ b/ios/chrome/browser/ui/omnibox/omnibox_util.mm
@@ -105,7 +105,7 @@
     security_state::SecurityLevel security_level) {
   switch (security_level) {
     case security_state::NONE:
-    case security_state::HTTP_SHOW_WARNING:
+    case security_state::WARNING:
       return INSECURE;
     case security_state::EV_SECURE:
     case security_state::SECURE:
@@ -187,7 +187,7 @@
 int GetIconForSecurityState(security_state::SecurityLevel security_level) {
   switch (security_level) {
     case security_state::NONE:
-    case security_state::HTTP_SHOW_WARNING:
+    case security_state::WARNING:
       return IDR_IOS_OMNIBOX_HTTP;
     case security_state::EV_SECURE:
     case security_state::SECURE:
diff --git a/ios/chrome/browser/web/image_fetch_tab_helper_unittest.mm b/ios/chrome/browser/web/image_fetch_tab_helper_unittest.mm
index ed2f9d7b..81b67da 100644
--- a/ios/chrome/browser/web/image_fetch_tab_helper_unittest.mm
+++ b/ios/chrome/browser/web/image_fetch_tab_helper_unittest.mm
@@ -10,6 +10,7 @@
 #import "ios/web/public/test/web_test_with_web_state.h"
 #include "net/http/http_util.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 #include "services/network/test/test_url_loader_factory.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/gtest_mac.h"
@@ -48,17 +49,18 @@
         base::MakeRefCounted<network::WeakWrapperSharedURLLoaderFactory>(
             &test_url_loader_factory_));
 
-    network::ResourceResponseHead head;
+    network::mojom::URLResponseHeadPtr head =
+        network::mojom::URLResponseHead::New();
     std::string raw_header =
         "HTTP/1.1 200 OK\n"
         "Content-type: image/png\n\n";
-    head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+    head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
         net::HttpUtil::AssembleRawHeaders(raw_header));
-    head.mime_type = "image/png";
+    head->mime_type = "image/png";
     network::URLLoaderCompletionStatus status;
     status.decoded_body_length = strlen(kImageData);
-    test_url_loader_factory_.AddResponse(GURL(kImageUrl), head, kImageData,
-                                         status);
+    test_url_loader_factory_.AddResponse(GURL(kImageUrl), std::move(head),
+                                         kImageData, status);
   }
 
   ImageFetchTabHelper* image_fetch_tab_helper() {
diff --git a/ios/testing/data/http_server_files/context_menu.html b/ios/testing/data/http_server_files/context_menu.html
index fb091d1..8a2b12a 100644
--- a/ios/testing/data/http_server_files/context_menu.html
+++ b/ios/testing/data/http_server_files/context_menu.html
@@ -13,7 +13,7 @@
   </div>
   <!-- mirror elements above with style="-webkit-touch-callout: none" -->
   <div style="-webkit-touch-callout: none">
-    <a id="no-webkit-link" href="/destination.html" style="-webkit-touch-callout: none">no-webkit-link-text</a>
+    <a id="no-webkit-link" href="/destination.html" style="-webkit-touch-callout: default">no-webkit-link-text</a>
   </div>
 </body>
 </html>
diff --git a/ios/web/web_state/js/resources/all_frames_context_menu.js b/ios/web/web_state/js/resources/all_frames_context_menu.js
index 9d5bcf9..64bc859 100644
--- a/ios/web/web_state/js/resources/all_frames_context_menu.js
+++ b/ios/web/web_state/js/resources/all_frames_context_menu.js
@@ -265,10 +265,10 @@
  * @return {Object}
  */
 var spiralCoordinates_ = function(x, y) {
-  var MAX_ANGLE = Math.PI * 2.0 * 3.0;
-  var POINT_COUNT = 30;
+  var MAX_ANGLE = Math.PI * 2.0 * 2.0;
+  var POINT_COUNT = 10;
   var ANGLE_STEP = MAX_ANGLE / POINT_COUNT;
-  var TOUCH_MARGIN = 25;
+  var TOUCH_MARGIN = 15;
   var SPEED = TOUCH_MARGIN / MAX_ANGLE;
 
   var coordinates = [];
diff --git a/media/filters/fuchsia/fuchsia_video_decoder.cc b/media/filters/fuchsia/fuchsia_video_decoder.cc
index e9e1bb3..c16a96c 100644
--- a/media/filters/fuchsia/fuchsia_video_decoder.cc
+++ b/media/filters/fuchsia/fuchsia_video_decoder.cc
@@ -8,6 +8,7 @@
 #include <fuchsia/mediacodec/cpp/fidl.h>
 #include <fuchsia/sysmem/cpp/fidl.h>
 #include <lib/sys/cpp/component_context.h>
+#include <vulkan/vulkan.h>
 #include <zircon/rights.h>
 
 #include "base/bind.h"
@@ -819,16 +820,19 @@
 
   VideoPixelFormat pixel_format;
   gfx::BufferFormat buffer_format;
+  VkFormat vk_format;
   switch (sysmem_pixel_format) {
     case fuchsia::sysmem::PixelFormatType::NV12:
       pixel_format = PIXEL_FORMAT_NV12;
       buffer_format = gfx::BufferFormat::YUV_420_BIPLANAR;
+      vk_format = VK_FORMAT_G8_B8R8_2PLANE_420_UNORM;
       break;
 
     case fuchsia::sysmem::PixelFormatType::I420:
     case fuchsia::sysmem::PixelFormatType::YV12:
       pixel_format = PIXEL_FORMAT_I420;
       buffer_format = gfx::BufferFormat::YVU_420;
+      vk_format = VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM;
       break;
 
     default:
@@ -896,6 +900,18 @@
                      base::Unretained(this), buffer_index,
                      output_packet.header().packet_index()));
 
+  // Currently sysmem doesn't specify location of chroma samples relative to
+  // luma (see fxb/13677). Assume they are cosited with luma. YCbCr info here
+  // must match the values passed for the same buffer in
+  // ui::SysmemBufferCollection::CreateVkImage() (see
+  // ui/ozone/platform/scenic/sysmem_buffer_collection.cc). |format_features|
+  // are resolved later in the GPU process before this info is passed to Skia.
+  frame->set_ycbcr_info(gpu::VulkanYCbCrInfo(
+      vk_format, /*external_format=*/0,
+      VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709,
+      VK_SAMPLER_YCBCR_RANGE_ITU_NARROW, VK_CHROMA_LOCATION_COSITED_EVEN,
+      VK_CHROMA_LOCATION_COSITED_EVEN, /*format_features=*/0));
+
   // Mark the frame as power-efficient when software decoders are disabled. The
   // codec may still decode on hardware even when |enable_sw_decoding_| is set
   // (i.e. POWER_EFFICIENT flag would not be set correctly in that case). It
diff --git a/media/gpu/windows/dxva_video_decode_accelerator_win.cc b/media/gpu/windows/dxva_video_decode_accelerator_win.cc
index 365b1d52..ac986b28 100644
--- a/media/gpu/windows/dxva_video_decode_accelerator_win.cc
+++ b/media/gpu/windows/dxva_video_decode_accelerator_win.cc
@@ -517,6 +517,7 @@
       use_dx11_(false),
       use_keyed_mutex_(false),
       using_angle_device_(false),
+      using_debug_device_(false),
       enable_accelerated_vpx_decode_(
           !workarounds.disable_accelerated_vpx_decode),
       processing_config_changed_(false) {
@@ -852,6 +853,7 @@
       RETURN_ON_HR_FAILURE(hr, "Failed to create debug DX11 device", false);
     }
 #endif
+    using_debug_device_ = !!d3d11_device_context_;
     if (!d3d11_device_context_) {
       hr = D3D11CreateDevice(NULL, D3D_DRIVER_TYPE_HARDWARE, NULL, flags,
                              feature_levels, base::size(feature_levels),
@@ -1856,6 +1858,35 @@
     client_->NotifyError(error);
   client_ = NULL;
 
+#ifdef _DEBUG
+  if (using_debug_device_) {
+    // MSDN says that this needs to be casted twice, then GetMessage should
+    // be called with a malloc.
+    Microsoft::WRL::ComPtr<ID3D11Debug> debug_layer;
+    if (SUCCEEDED(d3d11_device_.As(&debug_layer))) {
+      Microsoft::WRL::ComPtr<ID3D11InfoQueue> message_layer;
+      if (SUCCEEDED(debug_layer.As(&message_layer))) {
+        uint64_t message_count = message_layer->GetNumStoredMessages();
+        for (uint64_t i = 0; i < message_count; i++) {
+          SIZE_T message_size;
+          message_layer->GetMessage(i, nullptr, &message_size);
+          D3D11_MESSAGE* message =
+              reinterpret_cast<D3D11_MESSAGE*>(malloc(message_size));
+          if (message) {
+            message_layer->GetMessage(i, message, &message_size);
+            if (media_log_) {
+              MEDIA_LOG(INFO, media_log_) << message->pDescription;
+            } else {
+              DVLOG(1) << message->pDescription;
+            }
+            free(message);
+          }
+        }
+      }
+    }
+  }
+#endif
+
   if (GetState() != kUninitialized) {
     Invalidate();
   }
diff --git a/media/gpu/windows/dxva_video_decode_accelerator_win.h b/media/gpu/windows/dxva_video_decode_accelerator_win.h
index b6b41eb3..917cadf 100644
--- a/media/gpu/windows/dxva_video_decode_accelerator_win.h
+++ b/media/gpu/windows/dxva_video_decode_accelerator_win.h
@@ -158,6 +158,20 @@
     kMaxValue = BIND
   };
 
+  enum class DXVALifetimeProgression {
+    kInitializeStarted = 0,
+    kInitializeSucceeded = 1,
+    kPlaybackSucceeded = 2,
+
+    // For UMA. Must be the last entry. It should be initialized to the
+    // numerically largest value above; if you add more entries, then please
+    // update this to the last one.
+    kMaxValue = kPlaybackSucceeded
+  };
+
+  // Log UMA progression state.
+  void AddLifetimeProgressionStage(DXVALifetimeProgression stage);
+
   // Creates and initializes an instance of the D3D device and the
   // corresponding device manager. The device manager instance is eventually
   // passed to the IMFTransform interface implemented by the decoder.
@@ -402,6 +416,7 @@
 
   int processor_width_ = 0;
   int processor_height_ = 0;
+  bool already_initialized_ = false;
 
   Microsoft::WRL::ComPtr<IDirectXVideoProcessorService>
       video_processor_service_;
@@ -559,6 +574,7 @@
 
   // Set to true if we are sharing ANGLE's device.
   bool using_angle_device_;
+  bool using_debug_device_;
 
   // Enables hardware acceleration for VP9 video decoding.
   const bool enable_accelerated_vpx_decode_;
diff --git a/media/mojo/mojom/content_decryption_module.mojom b/media/mojo/mojom/content_decryption_module.mojom
index 925255e..1e0247d 100644
--- a/media/mojo/mojom/content_decryption_module.mojom
+++ b/media/mojo/mojom/content_decryption_module.mojom
@@ -146,5 +146,5 @@
   // It should be a reverse domain name, e.g. "com.example.somesystem". However,
   // this call may be initiated by an untrusted process (e.g. renderer), so the
   // implementation must fully validate |key_system| before creating the CDM.
-  CreateCdm(string key_system, ContentDecryptionModule& cdm);
+  CreateCdm(string key_system, pending_receiver<ContentDecryptionModule> cdm);
 };
diff --git a/media/mojo/services/cdm_service.cc b/media/mojo/services/cdm_service.cc
index 36a58b5..0c1d80e6 100644
--- a/media/mojo/services/cdm_service.cc
+++ b/media/mojo/services/cdm_service.cc
@@ -11,6 +11,8 @@
 #include "media/media_buildflags.h"
 #include "media/mojo/services/mojo_cdm_service.h"
 #include "media/mojo/services/mojo_cdm_service_context.h"
+#include "mojo/public/cpp/bindings/pending_receiver.h"
+#include "mojo/public/cpp/bindings/unique_receiver_set.h"
 #include "services/service_manager/public/cpp/connector.h"
 
 #if defined(OS_MACOSX)
@@ -41,7 +43,7 @@
 //     during browser shutdown, when the Cdservice could be destroyed directly,
 //     ignoring any outstanding ServiceKeepaliveRefs.
 //   - mojo::CdmFactory connection error happens, AND CdmFactoryImpl doesn't own
-//     any CDMs (|cdm_bindings_| is empty). This is to prevent destroying the
+//     any CDMs (|cdm_receivers_| is empty). This is to prevent destroying the
 //     CDMs too early (e.g. during page navigation) which could cause errors
 //     (session closed) on the client side. See https://crbug.com/821171 for
 //     details.
@@ -55,35 +57,36 @@
         keepalive_ref_(std::move(keepalive_ref)) {
     DVLOG(1) << __func__;
 
-    // base::Unretained is safe because |cdm_bindings_| is owned by |this|. If
-    // |this| is destructed, |cdm_bindings_| will be destructed as well and the
+    // base::Unretained is safe because |cdm_receivers_| is owned by |this|. If
+    // |this| is destructed, |cdm_receivers_| will be destructed as well and the
     // error handler should never be called.
-    cdm_bindings_.set_connection_error_handler(base::BindRepeating(
+    cdm_receivers_.set_disconnect_handler(base::BindRepeating(
         &CdmFactoryImpl::OnBindingConnectionError, base::Unretained(this)));
   }
 
   ~CdmFactoryImpl() final { DVLOG(1) << __func__; }
 
   // mojom::CdmFactory implementation.
-  void CreateCdm(const std::string& key_system,
-                 mojom::ContentDecryptionModuleRequest request) final {
+  void CreateCdm(
+      const std::string& key_system,
+      mojo::PendingReceiver<mojom::ContentDecryptionModule> receiver) final {
     DVLOG(2) << __func__;
 
     auto* cdm_factory = GetCdmFactory();
     if (!cdm_factory)
       return;
 
-    cdm_bindings_.AddBinding(
+    cdm_receivers_.Add(
         std::make_unique<MojoCdmService>(cdm_factory, &cdm_service_context_),
-        std::move(request));
+        std::move(receiver));
   }
 
   // DeferredDestroy<mojom::CdmFactory> implemenation.
   void OnDestroyPending(base::OnceClosure destroy_cb) final {
     destroy_cb_ = std::move(destroy_cb);
-    if (cdm_bindings_.empty())
+    if (cdm_receivers_.empty())
       std::move(destroy_cb_).Run();
-    // else the callback will be called when |cdm_bindings_| become empty.
+    // else the callback will be called when |cdm_receivers_| become empty.
   }
 
  private:
@@ -96,7 +99,7 @@
   }
 
   void OnBindingConnectionError() {
-    if (destroy_cb_ && cdm_bindings_.empty())
+    if (destroy_cb_ && cdm_receivers_.empty())
       std::move(destroy_cb_).Run();
   }
 
@@ -107,7 +110,7 @@
 
   CdmService::Client* client_;
   service_manager::mojom::InterfaceProviderPtr interfaces_;
-  mojo::StrongBindingSet<mojom::ContentDecryptionModule> cdm_bindings_;
+  mojo::UniqueReceiverSet<mojom::ContentDecryptionModule> cdm_receivers_;
   std::unique_ptr<ServiceKeepaliveRef> keepalive_ref_;
   std::unique_ptr<media::CdmFactory> cdm_factory_;
   base::OnceClosure destroy_cb_;
diff --git a/media/renderers/video_resource_updater.cc b/media/renderers/video_resource_updater.cc
index 80aaa6f..27baa1c 100644
--- a/media/renderers/video_resource_updater.cc
+++ b/media/renderers/video_resource_updater.cc
@@ -633,7 +633,7 @@
       stream_video_quad->SetNew(shared_quad_state, quad_rect, visible_quad_rect,
                                 needs_blending, frame_resources_[0].id,
                                 frame_resources_[0].size_in_pixels, uv_top_left,
-                                uv_bottom_right, frame->ycbcr_info());
+                                uv_bottom_right);
       for (viz::ResourceId resource_id : stream_video_quad->resources) {
         resource_provider_->ValidateResource(resource_id);
       }
@@ -846,6 +846,7 @@
           video_frame->metadata()->IsTrue(
               VideoFrameMetadata::READ_LOCK_FENCES_ENABLED);
       transfer_resource.format = viz::GetResourceFormat(buffer_formats[i]);
+      transfer_resource.ycbcr_info = video_frame->ycbcr_info();
 
 #if defined(OS_ANDROID)
       transfer_resource.is_backed_by_surface_texture =
diff --git a/net/dns/context_host_resolver.cc b/net/dns/context_host_resolver.cc
index 2d32399d..fddb9fc 100644
--- a/net/dns/context_host_resolver.cc
+++ b/net/dns/context_host_resolver.cc
@@ -112,6 +112,10 @@
     (*active_requests_.begin())->Cancel();
 }
 
+void ContextHostResolver::OnShutdown() {
+  // TODO(crbug.com/1006902): Implement.
+}
+
 std::unique_ptr<HostResolver::ResolveHostRequest>
 ContextHostResolver::CreateRequest(
     const HostPortPair& host,
diff --git a/net/dns/context_host_resolver.h b/net/dns/context_host_resolver.h
index efc1813..83a97554 100644
--- a/net/dns/context_host_resolver.h
+++ b/net/dns/context_host_resolver.h
@@ -42,6 +42,7 @@
   ~ContextHostResolver() override;
 
   // HostResolver methods:
+  void OnShutdown() override;
   std::unique_ptr<ResolveHostRequest> CreateRequest(
       const HostPortPair& host,
       const NetLogWithSource& net_log,
diff --git a/net/dns/host_resolver.h b/net/dns/host_resolver.h
index d445710..6225841a 100644
--- a/net/dns/host_resolver.h
+++ b/net/dns/host_resolver.h
@@ -270,6 +270,12 @@
   // be called.
   virtual ~HostResolver();
 
+  // Cancels any pending requests without calling callbacks, same as
+  // destruction, except also leaves the resolver in a mostly-noop state. Any
+  // future request Start() calls (for requests created before or after
+  // OnShutdown()) will immediately fail with ERR_CONTEXT_SHUT_DOWN.
+  virtual void OnShutdown() = 0;
+
   // Creates a request to resolve the given hostname (or IP address literal).
   // Profiling information for the request is saved to |net_log| if non-NULL.
   //
diff --git a/net/dns/mapped_host_resolver.cc b/net/dns/mapped_host_resolver.cc
index af5525a..78cfb7e 100644
--- a/net/dns/mapped_host_resolver.cc
+++ b/net/dns/mapped_host_resolver.cc
@@ -57,6 +57,10 @@
 
 MappedHostResolver::~MappedHostResolver() = default;
 
+void MappedHostResolver::OnShutdown() {
+  impl_->OnShutdown();
+}
+
 std::unique_ptr<HostResolver::ResolveHostRequest>
 MappedHostResolver::CreateRequest(
     const HostPortPair& host,
diff --git a/net/dns/mapped_host_resolver.h b/net/dns/mapped_host_resolver.h
index ced94f2..264da0e 100644
--- a/net/dns/mapped_host_resolver.h
+++ b/net/dns/mapped_host_resolver.h
@@ -28,6 +28,8 @@
   explicit MappedHostResolver(std::unique_ptr<HostResolver> impl);
   ~MappedHostResolver() override;
 
+  void OnShutdown() override;
+
   // Adds a rule to this mapper. The format of the rule can be one of:
   //
   //   "MAP" <hostname_pattern> <replacement_host> [":" <replacement_port>]
diff --git a/net/dns/mock_host_resolver.cc b/net/dns/mock_host_resolver.cc
index f349039..8a24ea1 100644
--- a/net/dns/mock_host_resolver.cc
+++ b/net/dns/mock_host_resolver.cc
@@ -272,6 +272,11 @@
   DCHECK(requests_.empty());
 }
 
+void MockHostResolverBase::OnShutdown() {
+  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
+  // TODO(crbug.com/1006902): Implement.
+}
+
 std::unique_ptr<HostResolver::ResolveHostRequest>
 MockHostResolverBase::CreateRequest(
     const HostPortPair& host,
@@ -932,6 +937,10 @@
 
 HangingHostResolver::~HangingHostResolver() = default;
 
+void HangingHostResolver::OnShutdown() {
+  // TODO(crbug.com/1006902): Implement.
+}
+
 std::unique_ptr<HostResolver::ResolveHostRequest>
 HangingHostResolver::CreateRequest(
     const HostPortPair& host,
diff --git a/net/dns/mock_host_resolver.h b/net/dns/mock_host_resolver.h
index 755d5b7..f4425c7d2 100644
--- a/net/dns/mock_host_resolver.h
+++ b/net/dns/mock_host_resolver.h
@@ -113,6 +113,7 @@
   }
 
   // HostResolver methods:
+  void OnShutdown() override;
   std::unique_ptr<ResolveHostRequest> CreateRequest(
       const HostPortPair& host,
       const NetLogWithSource& net_log,
@@ -447,6 +448,7 @@
  public:
   HangingHostResolver();
   ~HangingHostResolver() override;
+  void OnShutdown() override;
   std::unique_ptr<ResolveHostRequest> CreateRequest(
       const HostPortPair& host,
       const NetLogWithSource& net_log,
diff --git a/net/log/net_log_event_type_list.h b/net/log/net_log_event_type_list.h
index 9d9dac6..f212fdd0 100644
--- a/net/log/net_log_event_type_list.h
+++ b/net/log/net_log_event_type_list.h
@@ -2027,6 +2027,38 @@
 //  }
 EVENT_TYPE(QUIC_SESSION_STOP_SENDING_FRAME_RECEIVED)
 
+// Session sent a STREAMS_BLOCKED frame.
+//  {
+//    "stream_count": <The number of streams that the sender wishes to exceed>
+//    "unidirectional": <boolean to indicate if the frame is for unidirectional
+//    streams.>
+//  }
+EVENT_TYPE(QUIC_SESSION_STREAMS_BLOCKED_FRAME_SENT)
+
+// Session received a STREAMS_BLOCKED frame.
+//  {
+//    "stream_count": <The number of streams that the sender wishes to exceed>
+//    "unidirectional": <boolean to indicate if the frame is for unidirectional
+//    streams.>
+//  }
+EVENT_TYPE(QUIC_SESSION_STREAMS_BLOCKED_FRAME_RECEIVED)
+
+// Session sent a MAX_STREAMS frame.
+//  {
+//    "stream_count": <The number of streams that may be opened>
+//    "unidirectional": <boolean to indicate if the frame is for unidirectional
+//    streams.>
+//  }
+EVENT_TYPE(QUIC_SESSION_MAX_STREAMS_FRAME_SENT)
+
+// Session received a MAX_STREAMS frame.
+//  {
+//    "stream_count": <The number of streams that may be opened>
+//    "unidirectional": <boolean to indicate if the frame is for unidirectional
+//    streams.>
+//  }
+EVENT_TYPE(QUIC_SESSION_MAX_STREAMS_FRAME_RECEIVED)
+
 // ------------------------------------------------------------------------
 // QuicHttpStream
 // ------------------------------------------------------------------------
diff --git a/net/quic/quic_connection_logger.cc b/net/quic/quic_connection_logger.cc
index fa7230b..7845dcc 100644
--- a/net/quic/quic_connection_logger.cc
+++ b/net/quic/quic_connection_logger.cc
@@ -149,6 +149,7 @@
   base::Value dict(base::Value::Type::DICTIONARY);
   dict.SetIntKey("stream_id", frame->stream_id);
   dict.SetIntKey("quic_rst_stream_error", frame->error_code);
+  dict.SetKey("offset", NetLogNumberValue(frame->byte_offset));
   return dict;
 }
 
@@ -245,12 +246,18 @@
   return dict;
 }
 
-base::Value NetLogQuicCryptoFrameParams(const quic::QuicCryptoFrame* frame) {
+base::Value NetLogQuicCryptoFrameParams(const quic::QuicCryptoFrame* frame,
+                                        bool has_buffer) {
   base::Value dict(base::Value::Type::DICTIONARY);
   dict.SetStringKey("encryption_level",
                     quic::QuicUtils::EncryptionLevelToString(frame->level));
   dict.SetIntKey("data_length", frame->data_length);
   dict.SetKey("offset", NetLogNumberValue(frame->offset));
+  if (has_buffer) {
+    dict.SetKey("bytes", NetLogBinaryValue(
+                             reinterpret_cast<const void*>(frame->data_buffer),
+                             frame->data_length));
+  }
   return dict;
 }
 
@@ -262,6 +269,22 @@
   return dict;
 }
 
+base::Value NetLogQuicStreamsBlockedFrameParams(
+    const quic::QuicStreamsBlockedFrame& frame) {
+  base::Value dict(base::Value::Type::DICTIONARY);
+  dict.SetIntKey("stream_count", frame.stream_count);
+  dict.SetBoolKey("is_unidirectional", frame.unidirectional);
+  return dict;
+}
+
+base::Value NetLogQuicMaxStreamsFrameParams(
+    const quic::QuicMaxStreamsFrame& frame) {
+  base::Value dict(base::Value::Type::DICTIONARY);
+  dict.SetIntKey("stream_count", frame.stream_count);
+  dict.SetBoolKey("is_unidirectional", frame.unidirectional);
+  return dict;
+}
+
 void UpdatePublicResetAddressMismatchHistogram(
     const IPEndPoint& server_hello_address,
     const IPEndPoint& public_reset_address) {
@@ -470,8 +493,17 @@
     case quic::NEW_CONNECTION_ID_FRAME:
       break;
     case quic::MAX_STREAMS_FRAME:
+      net_log_.AddEvent(
+          NetLogEventType::QUIC_SESSION_MAX_STREAMS_FRAME_SENT, [&] {
+            return NetLogQuicMaxStreamsFrameParams(frame.max_streams_frame);
+          });
       break;
     case quic::STREAMS_BLOCKED_FRAME:
+      net_log_.AddEvent(
+          NetLogEventType::QUIC_SESSION_STREAMS_BLOCKED_FRAME_SENT, [&] {
+            return NetLogQuicStreamsBlockedFrameParams(
+                frame.streams_blocked_frame);
+          });
       break;
     case quic::PATH_RESPONSE_FRAME:
       break;
@@ -487,7 +519,8 @@
       break;
     case quic::CRYPTO_FRAME:
       net_log_.AddEvent(NetLogEventType::QUIC_SESSION_CRYPTO_FRAME_SENT, [&] {
-        return NetLogQuicCryptoFrameParams(frame.crypto_frame);
+        return NetLogQuicCryptoFrameParams(frame.crypto_frame,
+                                           /*has_buffer = */ false);
       });
       break;
     case quic::NEW_TOKEN_FRAME:
@@ -652,8 +685,9 @@
 void QuicConnectionLogger::OnCryptoFrame(const quic::QuicCryptoFrame& frame) {
   if (!net_log_.IsCapturing())
     return;
-  net_log_.AddEvent(NetLogEventType::QUIC_SESSION_CRYPTO_FRAME_RECEIVED,
-                    [&] { return NetLogQuicCryptoFrameParams(&frame); });
+  net_log_.AddEvent(NetLogEventType::QUIC_SESSION_CRYPTO_FRAME_RECEIVED, [&] {
+    return NetLogQuicCryptoFrameParams(&frame, /*has_buffer = */ true);
+  });
 }
 
 void QuicConnectionLogger::OnStopSendingFrame(
@@ -664,6 +698,23 @@
                     [&] { return NetLogQuicStopSendingFrameParams(&frame); });
 }
 
+void QuicConnectionLogger::OnStreamsBlockedFrame(
+    const quic::QuicStreamsBlockedFrame& frame) {
+  if (!net_log_.IsCapturing())
+    return;
+  net_log_.AddEvent(
+      NetLogEventType::QUIC_SESSION_STREAMS_BLOCKED_FRAME_RECEIVED,
+      [&] { return NetLogQuicStreamsBlockedFrameParams(frame); });
+}
+
+void QuicConnectionLogger::OnMaxStreamsFrame(
+    const quic::QuicMaxStreamsFrame& frame) {
+  if (!net_log_.IsCapturing())
+    return;
+  net_log_.AddEvent(NetLogEventType::QUIC_SESSION_MAX_STREAMS_FRAME_RECEIVED,
+                    [&] { return NetLogQuicMaxStreamsFrameParams(frame); });
+}
+
 void QuicConnectionLogger::OnIncomingAck(
     quic::QuicPacketNumber ack_packet_number,
     const quic::QuicAckFrame& frame,
diff --git a/net/quic/quic_connection_logger.h b/net/quic/quic_connection_logger.h
index 8045ce6..02b3378 100644
--- a/net/quic/quic_connection_logger.h
+++ b/net/quic/quic_connection_logger.h
@@ -71,6 +71,9 @@
   void OnPacketHeader(const quic::QuicPacketHeader& header) override;
   void OnCryptoFrame(const quic::QuicCryptoFrame& frame) override;
   void OnStopSendingFrame(const quic::QuicStopSendingFrame& frame) override;
+  void OnStreamsBlockedFrame(
+      const quic::QuicStreamsBlockedFrame& frame) override;
+  void OnMaxStreamsFrame(const quic::QuicMaxStreamsFrame& frame) override;
   void OnStreamFrame(const quic::QuicStreamFrame& frame) override;
   void OnStopWaitingFrame(const quic::QuicStopWaitingFrame& frame) override;
   void OnRstStreamFrame(const quic::QuicRstStreamFrame& frame) override;
diff --git a/net/quic/quic_flags_list.h b/net/quic/quic_flags_list.h
index da86be66..f7449e1 100644
--- a/net/quic/quic_flags_list.h
+++ b/net/quic/quic_flags_list.h
@@ -255,7 +255,7 @@
 // frames.
 QUIC_FLAG(
     bool,
-    FLAGS_quic_reloadable_flag_quic_add_upper_limit_of_buffered_control_frames2,
+    FLAGS_quic_reloadable_flag_quic_add_upper_limit_of_buffered_control_frames3,
     false)
 
 // If true, static streams should never be closed before QuicSession
@@ -291,7 +291,7 @@
 // closed streams whose highest byte offset is not received yet.
 QUIC_FLAG(bool,
           FLAGS_quic_reloadable_flag_quic_aggressive_connection_aliveness,
-          false)
+          true)
 
 // If true, QuicStreamSequencer will not take in new data if the stream is
 // reset.
@@ -341,29 +341,27 @@
 
 // If true, deprecate SpuriousRetransmitDetected and call SpuriousLossDetected
 // instead.
-QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_detect_spurious_loss, false)
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_detect_spurious_loss, true)
 
 // If true, a stream will reset itself if it receives a stream frame that
 // includes a data beyond the close offset.
 QUIC_FLAG(
     bool,
     FLAGS_quic_reloadable_flag_quic_rst_if_stream_frame_beyond_close_offset,
-    false)
+    true)
 
 // If true, enable IETF loss detection as described in
 // https://tools.ietf.org/html/draft-ietf-quic-recovery-22#section-6.1.
 QUIC_FLAG(bool,
           FLAGS_quic_reloadable_flag_quic_enable_ietf_loss_detection,
-          false)
+          true)
 
 // If true, skip packet number before sending the last PTO retransmission.
 QUIC_FLAG(bool,
           FLAGS_quic_reloadable_flag_quic_skip_packet_number_for_pto,
-          false)
+          true)
 // If true, enable HTTP/2 default scheduling(round robin).
-QUIC_FLAG(bool,
-          FLAGS_quic_reloadable_flag_quic_enable_rr_write_scheduler,
-          false)
+QUIC_FLAG(bool, FLAGS_quic_reloadable_flag_quic_enable_rr_write_scheduler, true)
 
 // If true, when timer fires in RTO or PTO mode, make sure there is enough
 // credits to retransmit one packet.
diff --git a/net/quic/quic_http3_logger.cc b/net/quic/quic_http3_logger.cc
index 45233a0..ee7a22aa 100644
--- a/net/quic/quic_http3_logger.cc
+++ b/net/quic/quic_http3_logger.cc
@@ -21,7 +21,10 @@
   base::Value dict(base::Value::Type::DICTIONARY);
   // TODO(renjietang): Use string literal for setting identifiers.
   for (auto setting : frame.values) {
-    dict.SetIntKey(base::NumberToString(setting.first), setting.second);
+    dict.SetIntKey(
+        quic::SpdyUtils::H3SettingsToString(
+            static_cast<quic::Http3AndQpackSettingsIdentifiers>(setting.first)),
+        setting.second);
   }
   return dict;
 }
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc
index 69e3099e..8a999db 100644
--- a/net/quic/quic_network_transaction_unittest.cc
+++ b/net/quic/quic_network_transaction_unittest.cc
@@ -1283,10 +1283,6 @@
 }
 
 TEST_P(QuicNetworkTransactionTest, LargeResponseHeaders) {
-  // TODO(rch): honor the max header list size. b/136108828
-  if (quic::VersionUsesQpack(version_.transport_version))
-    return;
-
   session_params_.quic_params.origins_to_force_quic_on.insert(
       HostPortPair::FromString("mail.example.org:443"));
 
@@ -2469,7 +2465,7 @@
 
 TEST_P(QuicNetworkTransactionTest, GoAwayWithConnectionMigrationOnPortsOnly) {
   if (version_.transport_version == quic::QUIC_VERSION_99) {
-    // Not available under version 99
+    // GoAway is not available under version 99
     return;
   }
   MockQuicData mock_quic_data(version_);
@@ -8886,8 +8882,7 @@
   }
 
   if (quic::VersionUsesQpack(version_.transport_version)) {
-    // TODO(rch): both stream_dependencies and priority frames need to be
-    // supported in IETF QUIC.
+    // HTTP/3 currently doesn't support PRIORITY.
     return;
   }
 
diff --git a/net/url_request/url_request_context.h b/net/url_request/url_request_context.h
index 77f1bbab..3e4b923 100644
--- a/net/url_request/url_request_context.h
+++ b/net/url_request/url_request_context.h
@@ -128,6 +128,7 @@
   }
 
   void set_host_resolver(HostResolver* host_resolver) {
+    DCHECK(host_resolver);
     host_resolver_ = host_resolver;
   }
 
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc
index 57dad1c4..640a708 100644
--- a/net/url_request/url_request_context_builder.cc
+++ b/net/url_request/url_request_context_builder.cc
@@ -151,6 +151,9 @@
     // down before this cancels the ProxyResolutionService's URLRequests.
     proxy_resolution_service()->OnShutdown();
 
+    DCHECK(host_resolver());
+    host_resolver()->OnShutdown();
+
     AssertNoURLRequests();
   }
 
diff --git a/remoting/client/notification/BUILD.gn b/remoting/client/notification/BUILD.gn
index a49c4d7..e8cfae11 100644
--- a/remoting/client/notification/BUILD.gn
+++ b/remoting/client/notification/BUILD.gn
@@ -15,10 +15,13 @@
     "version_range.h",
   ]
 
+  configs += [ "//remoting/build/config:version" ]
+
   deps = [
     "//base",
     "//net",
     "//remoting/base",
+    "//ui/base",
   ]
 }
 
diff --git a/remoting/client/notification/notification_client.cc b/remoting/client/notification/notification_client.cc
index 4dd1590..6f3cc77 100644
--- a/remoting/client/notification/notification_client.cc
+++ b/remoting/client/notification/notification_client.cc
@@ -10,16 +10,35 @@
 #include "base/logging.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/scoped_refptr.h"
+#include "base/strings/stringize_macros.h"
 #include "base/values.h"
+#include "build/build_config.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
-#include "remoting/client/notification/json_fetcher.h"
+#include "remoting/client/notification/gstatic_json_fetcher.h"
 #include "remoting/client/notification/notification_message.h"
 #include "remoting/client/notification/version_range.h"
+#include "ui/base/l10n/l10n_util.h"
 
 namespace remoting {
 
 namespace {
 
+#if defined(OS_IOS)
+constexpr char kCurrentPlatform[] = "IOS";
+#elif defined(OS_ANDROID)
+constexpr char kCurrentPlatform[] = "ANDROID";
+#else
+constexpr char kCurrentPlatform[] = "UNKNOWN";
+#endif
+
+constexpr char kCurrentVersion[] = STRINGIZE(VERSION);
+
+#if defined(NDEBUG)
+constexpr bool kShouldIgnoreDevMessages = true;
+#else
+constexpr bool kShouldIgnoreDevMessages = false;
+#endif
+
 constexpr char kDefaultLocale[] = "en-US";
 constexpr char kNotificationRootPath[] = "notification/";
 constexpr char kNotificationRulesPath[] = "notification/rules.json";
@@ -82,6 +101,11 @@
                        &base::Value::GetInt, "int");
 }
 
+bool FindKeyAndGet(const base::Value& dict, const std::string& key, bool* out) {
+  return FindKeyAndGet(dict, key, out, &base::Value::is_bool,
+                       &base::Value::GetBool, "bool");
+}
+
 bool ShouldShowNotificationForUser(const std::string& user_email,
                                    int percent_int) {
   DCHECK_GE(percent_int, 0);
@@ -160,16 +184,28 @@
 
 }  // namespace
 
+NotificationClient::NotificationClient()
+    : NotificationClient(std::make_unique<GstaticJsonFetcher>(),
+                         kCurrentPlatform,
+                         kCurrentVersion,
+                         l10n_util::GetApplicationLocale(""),
+                         kShouldIgnoreDevMessages) {}
+
 NotificationClient::~NotificationClient() = default;
 
 NotificationClient::NotificationClient(std::unique_ptr<JsonFetcher> fetcher,
                                        const std::string& current_platform,
                                        const std::string& current_version,
-                                       const std::string& locale)
+                                       const std::string& locale,
+                                       bool should_ignore_dev_messages)
     : fetcher_(std::move(fetcher)),
       current_platform_(current_platform),
       current_version_(current_version),
-      locale_(locale) {}
+      locale_(locale),
+      should_ignore_dev_messages_(should_ignore_dev_messages) {
+  VLOG(1) << "Platform: " << current_platform_
+          << ", version: " << current_version_ << ", locale: " << locale_;
+}
 
 void NotificationClient::GetNotification(const std::string& user_email,
                                          NotificationCallback callback) {
@@ -219,6 +255,7 @@
   std::string appearance_string;
   std::string target_platform;
   std::string version_spec_string;
+  std::string message_id;
   std::string message_text_filename;
   std::string link_text_filename;
   std::string link_url;
@@ -226,6 +263,7 @@
   if (!FindKeyAndGet(rule, "appearance", &appearance_string) ||
       !FindKeyAndGet(rule, "target_platform", &target_platform) ||
       !FindKeyAndGet(rule, "version", &version_spec_string) ||
+      !FindKeyAndGet(rule, "message_id", &message_id) ||
       !FindKeyAndGet(rule, "message_text", &message_text_filename) ||
       !FindKeyAndGet(rule, "link_text", &link_text_filename) ||
       !FindKeyAndGet(rule, "link_url", &link_url) ||
@@ -233,6 +271,13 @@
     return base::nullopt;
   }
 
+  if (should_ignore_dev_messages_) {
+    bool is_dev_mode;
+    if (FindKeyAndGet(rule, "dev_mode", &is_dev_mode) && is_dev_mode) {
+      return base::nullopt;
+    }
+  }
+
   if (target_platform != current_platform_) {
     VLOG(1) << "Notification ignored. Target platform: " << target_platform
             << "; current platform: " << current_platform_;
@@ -265,6 +310,7 @@
     LOG(ERROR) << "Unknown appearance: " << appearance_string;
     return base::nullopt;
   }
+  message->message_id = message_id;
   message->link_url = link_url;
   *out_message_text_filename = message_text_filename;
   *out_link_text_filename = link_text_filename;
diff --git a/remoting/client/notification/notification_client.h b/remoting/client/notification/notification_client.h
index 36f7231..21c0c330 100644
--- a/remoting/client/notification/notification_client.h
+++ b/remoting/client/notification/notification_client.h
@@ -28,6 +28,7 @@
   using NotificationCallback =
       base::OnceCallback<void(base::Optional<NotificationMessage>)>;
 
+  NotificationClient();
   ~NotificationClient();
 
   // Fetches notifications from the server and calls |callback| with the
@@ -45,7 +46,8 @@
   NotificationClient(std::unique_ptr<JsonFetcher> fetcher,
                      const std::string& current_platform,
                      const std::string& current_version,
-                     const std::string& locale);
+                     const std::string& locale,
+                     bool should_ignore_dev_messages);
 
   void OnRulesFetched(const std::string& user_email,
                       NotificationCallback callback,
@@ -69,6 +71,7 @@
   std::string current_platform_;
   std::string current_version_;
   std::string locale_;
+  bool should_ignore_dev_messages_;
 
   DISALLOW_COPY_AND_ASSIGN(NotificationClient);
 };
diff --git a/remoting/client/notification/notification_client_unittest.cc b/remoting/client/notification/notification_client_unittest.cc
index 519706a..0525f50 100644
--- a/remoting/client/notification/notification_client_unittest.cc
+++ b/remoting/client/notification/notification_client_unittest.cc
@@ -46,6 +46,7 @@
 
 MATCHER_P(MessageMatches, expected, "") {
   return arg->appearance == expected.appearance &&
+         arg->message_id == expected.message_id &&
          arg->message_text == expected.message_text &&
          arg->link_text == expected.link_text &&
          arg->link_url == expected.link_url;
@@ -61,6 +62,7 @@
   rule.SetStringKey("appearance", "TOAST");
   rule.SetStringKey("target_platform", "IOS");
   rule.SetStringKey("version", "[75-)");
+  rule.SetStringKey("message_id", "test_message");
   rule.SetStringKey("message_text", "message_text.json");
   rule.SetStringKey("link_text", "link_text.json");
   rule.SetStringKey("link_url", "https://example.com/some_link");
@@ -78,6 +80,7 @@
 NotificationMessage CreateDefaultNotification() {
   NotificationMessage message;
   message.appearance = NotificationMessage::Appearance::TOAST;
+  message.message_id = "test_message";
   message.message_text = "zh-CN:message";
   message.link_text = "zh-CN:link";
   message.link_url = "https://example.com/some_link";
@@ -88,16 +91,19 @@
 
 class NotificationClientTest : public ::testing::Test {
  public:
-  NotificationClientTest() {
-    auto fetcher = std::make_unique<MockJsonFetcher>();
-    fetcher_ = fetcher.get();
-    client_ = base::WrapUnique(new NotificationClient(
-        std::move(fetcher), kTestPlatform, kTestVersion, kTestLocale));
-  }
+  NotificationClientTest() { Reset(true); }
 
   ~NotificationClientTest() override = default;
 
  protected:
+  void Reset(bool should_ignore_dev_messages) {
+    auto fetcher = std::make_unique<MockJsonFetcher>();
+    fetcher_ = fetcher.get();
+    client_ = base::WrapUnique(
+        new NotificationClient(std::move(fetcher), kTestPlatform, kTestVersion,
+                               kTestLocale, should_ignore_dev_messages));
+  }
+
   MockJsonFetcher* fetcher_;
   std::unique_ptr<NotificationClient> client_;
 };
@@ -257,4 +263,53 @@
   client_->GetNotification(kTestEmail, callback.Get());
 }
 
+TEST_F(NotificationClientTest, ReleaseBuildsIgnoreDevMessages) {
+  base::Value rules(base::Value::Type::LIST);
+  base::Value rule = CreateDefaultRule();
+  rule.SetBoolKey("dev_mode", true);
+  rules.Append(std::move(rule));
+  EXPECT_CALL(*fetcher_, FetchJsonFile("notification/rules.json"))
+      .WillOnce(ReturnByMove(std::move(rules)));
+
+  base::MockCallback<NotificationClient::NotificationCallback> callback;
+  EXPECT_CALL(callback, Run(NoMessage()));
+  client_->GetNotification(kTestEmail, callback.Get());
+}
+
+TEST_F(NotificationClientTest, ReleaseBuildsDontIgnoreDevMessages) {
+  base::Value rules(base::Value::Type::LIST);
+  base::Value rule = CreateDefaultRule();
+  rule.SetBoolKey("dev_mode", false);
+  rules.Append(std::move(rule));
+  EXPECT_CALL(*fetcher_, FetchJsonFile("notification/rules.json"))
+      .WillOnce(ReturnByMove(std::move(rules)));
+  EXPECT_CALL(*fetcher_, FetchJsonFile("notification/message_text.json"))
+      .WillOnce(ReturnByMove(CreateDefaultTranslations("message")));
+  EXPECT_CALL(*fetcher_, FetchJsonFile("notification/link_text.json"))
+      .WillOnce(ReturnByMove(CreateDefaultTranslations("link")));
+
+  base::MockCallback<NotificationClient::NotificationCallback> callback;
+  EXPECT_CALL(callback, Run(MessageMatches(CreateDefaultNotification())));
+  client_->GetNotification(kTestEmail, callback.Get());
+}
+
+TEST_F(NotificationClientTest, DebugBuildsDontIgnoreDevMessages) {
+  Reset(/* should_ignore_dev_messages */ false);
+
+  base::Value rules(base::Value::Type::LIST);
+  base::Value rule = CreateDefaultRule();
+  rule.SetBoolKey("dev_mode", true);
+  rules.Append(std::move(rule));
+  EXPECT_CALL(*fetcher_, FetchJsonFile("notification/rules.json"))
+      .WillOnce(ReturnByMove(std::move(rules)));
+  EXPECT_CALL(*fetcher_, FetchJsonFile("notification/message_text.json"))
+      .WillOnce(ReturnByMove(CreateDefaultTranslations("message")));
+  EXPECT_CALL(*fetcher_, FetchJsonFile("notification/link_text.json"))
+      .WillOnce(ReturnByMove(CreateDefaultTranslations("link")));
+
+  base::MockCallback<NotificationClient::NotificationCallback> callback;
+  EXPECT_CALL(callback, Run(MessageMatches(CreateDefaultNotification())));
+  client_->GetNotification(kTestEmail, callback.Get());
+}
+
 }  // namespace remoting
\ No newline at end of file
diff --git a/remoting/client/notification/notification_message.h b/remoting/client/notification/notification_message.h
index ee28410..244e6ff 100644
--- a/remoting/client/notification/notification_message.h
+++ b/remoting/client/notification/notification_message.h
@@ -24,6 +24,7 @@
   NotificationMessage& operator=(NotificationMessage&&);
 
   Appearance appearance;
+  std::string message_id;
   std::string message_text;
   std::string link_text;
   std::string link_url;
diff --git a/remoting/host/gcd_rest_client_unittest.cc b/remoting/host/gcd_rest_client_unittest.cc
index a24260e9..57166bdf 100644
--- a/remoting/host/gcd_rest_client_unittest.cc
+++ b/remoting/host/gcd_rest_client_unittest.cc
@@ -97,7 +97,7 @@
   test_url_loader_factory_.SetInterceptor(
       base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
         test_url_loader_factory_.AddResponse(
-            request.url, network::ResourceResponseHead(), std::string(),
+            request.url, network::mojom::URLResponseHead::New(), std::string(),
             network::URLLoaderCompletionStatus(net::ERR_FAILED));
       }));
 
diff --git a/remoting/host/gcd_state_updater_unittest.cc b/remoting/host/gcd_state_updater_unittest.cc
index daf4d86..7d5db6f 100644
--- a/remoting/host/gcd_state_updater_unittest.cc
+++ b/remoting/host/gcd_state_updater_unittest.cc
@@ -166,14 +166,14 @@
 
   auto* request = GetPendingRequest(0);
   test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList(
-      request, network::ResourceResponseHead(), std::string(),
+      request, network::mojom::URLResponseHead::New(), std::string(),
       network::URLLoaderCompletionStatus(net::ERR_FAILED));
 
   task_environment_.FastForwardBy(base::TimeDelta::FromSeconds(1));
 
   request = GetPendingRequest(1);
   test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList(
-      request, network::CreateResourceResponseHead(net::HTTP_OK), std::string(),
+      request, network::CreateURLResponseHead(net::HTTP_OK), std::string(),
       network::URLLoaderCompletionStatus());
   EXPECT_EQ(1, on_success_count_);
 
@@ -193,7 +193,7 @@
 
   auto* request = GetPendingRequest(0);
   test_url_loader_factory_.SimulateResponseWithoutRemovingFromPendingList(
-      request, network::CreateResourceResponseHead(net::HTTP_NOT_FOUND),
+      request, network::CreateURLResponseHead(net::HTTP_NOT_FOUND),
       std::string(), network::URLLoaderCompletionStatus(net::OK));
   EXPECT_EQ(0, on_success_count_);
   EXPECT_EQ(1, on_host_id_error_count_);
diff --git a/remoting/test/access_token_fetcher_unittest.cc b/remoting/test/access_token_fetcher_unittest.cc
index f6852b3..c4fe7c2 100644
--- a/remoting/test/access_token_fetcher_unittest.cc
+++ b/remoting/test/access_token_fetcher_unittest.cc
@@ -111,7 +111,7 @@
                                              net::HttpStatusCode code,
                                              int net_error) {
   test_url_loader_factory_.AddResponse(
-      url, network::CreateResourceResponseHead(code), data,
+      url, network::CreateURLResponseHead(code), data,
       network::URLLoaderCompletionStatus(net_error));
 }
 
diff --git a/services/device/battery/android/java/src/org/chromium/device/battery/BatteryMonitorFactory.java b/services/device/battery/android/java/src/org/chromium/device/battery/BatteryMonitorFactory.java
index f90a5130..461cbb4 100644
--- a/services/device/battery/android/java/src/org/chromium/device/battery/BatteryMonitorFactory.java
+++ b/services/device/battery/android/java/src/org/chromium/device/battery/BatteryMonitorFactory.java
@@ -27,12 +27,18 @@
     // Monitors currently interested in the battery status notifications.
     private final HashSet<BatteryMonitorImpl> mSubscribedMonitors =
             new HashSet<BatteryMonitorImpl>();
+    // Tracks the latest battery status update for newly added observers.
+    private boolean mHasStatusUpdate;
+    private BatteryStatus mBatteryStatus;
 
     private final BatteryStatusCallback mCallback = new BatteryStatusCallback() {
         @Override
         public void onBatteryStatusChanged(BatteryStatus batteryStatus) {
             ThreadUtils.assertOnUiThread();
 
+            mHasStatusUpdate = true;
+            mBatteryStatus = batteryStatus;
+
             List<BatteryMonitorImpl> monitors = new ArrayList<>(mSubscribedMonitors);
             for (BatteryMonitorImpl monitor : monitors) {
                 monitor.didChange(batteryStatus);
@@ -41,6 +47,7 @@
     };
 
     public BatteryMonitorFactory() {
+        mHasStatusUpdate = false;
         mManager = new BatteryStatusManager(mCallback);
     }
 
@@ -55,6 +62,10 @@
         //            for UMA - http://crbug.com/442300.
 
         BatteryMonitorImpl monitor = new BatteryMonitorImpl(this);
+        if (mHasStatusUpdate) {
+            monitor.didChange(mBatteryStatus);
+        }
+
         mSubscribedMonitors.add(monitor);
         return monitor;
     }
@@ -66,6 +77,7 @@
         mSubscribedMonitors.remove(monitor);
         if (mSubscribedMonitors.isEmpty()) {
             mManager.stop();
+            mHasStatusUpdate = false;
         }
     }
 }
diff --git a/services/device/geolocation/network_location_provider_unittest.cc b/services/device/geolocation/network_location_provider_unittest.cc
index cb74d87..dc4ec5e 100644
--- a/services/device/geolocation/network_location_provider_unittest.cc
+++ b/services/device/geolocation/network_location_provider_unittest.cc
@@ -457,7 +457,7 @@
   const GURL& request_url_3 =
       test_url_loader_factory_.pending_requests()->back().request.url;
   test_url_loader_factory_.AddResponse(
-      request_url_3, network::ResourceResponseHead(), std::string(),
+      request_url_3, network::mojom::URLResponseHead::New(), std::string(),
       network::URLLoaderCompletionStatus(net::ERR_FAILED));
   base::RunLoop().RunUntilIdle();
 
diff --git a/services/network/cors/cors_url_loader_unittest.cc b/services/network/cors/cors_url_loader_unittest.cc
index 6157f88f..21b70e24 100644
--- a/services/network/cors/cors_url_loader_unittest.cc
+++ b/services/network/cors/cors_url_loader_unittest.cc
@@ -66,15 +66,15 @@
   void NotifyClientOnReceiveResponse(
       int status_code,
       const std::vector<std::string>& extra_headers) {
-    ResourceResponseHead response;
-    response.headers = new net::HttpResponseHeaders(
+    auto response = mojom::URLResponseHead::New();
+    response->headers = new net::HttpResponseHeaders(
         base::StringPrintf("HTTP/1.1 %d OK\n"
                            "Content-Type: image/png\n",
                            status_code));
     for (const auto& header : extra_headers)
-      response.headers->AddHeader(header);
+      response->headers->AddHeader(header);
 
-    client_ptr_->OnReceiveResponse(response);
+    client_ptr_->OnReceiveResponse(std::move(response));
   }
 
   void NotifyClientOnComplete(int error_code) {
@@ -85,13 +85,13 @@
   void NotifyClientOnReceiveRedirect(
       const net::RedirectInfo& redirect_info,
       const std::vector<std::string>& extra_headers) {
-    ResourceResponseHead response;
-    response.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+    auto response = mojom::URLResponseHead::New();
+    response->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
         base::StringPrintf("HTTP/1.1 %d\n", redirect_info.status_code));
     for (const auto& header : extra_headers)
-      response.headers->AddHeader(header);
+      response->headers->AddHeader(header);
 
-    client_ptr_->OnReceiveRedirect(redirect_info, response);
+    client_ptr_->OnReceiveRedirect(redirect_info, std::move(response));
   }
 
   bool IsCreateLoaderAndStartCalled() { return !!client_ptr_; }
@@ -1217,7 +1217,7 @@
   EXPECT_FALSE(client().has_received_redirect());
   EXPECT_TRUE(client().has_received_response());
   EXPECT_EQ(network::mojom::FetchResponseType::kBasic,
-            client().response_head().response_type);
+            client().response_head()->response_type);
   EXPECT_TRUE(client().has_received_completion());
   EXPECT_EQ(net::OK, client().completion_status().error_code);
 }
@@ -1251,7 +1251,7 @@
   EXPECT_FALSE(client().has_received_redirect());
   EXPECT_TRUE(client().has_received_response());
   EXPECT_EQ(network::mojom::FetchResponseType::kBasic,
-            client().response_head().response_type);
+            client().response_head()->response_type);
   EXPECT_TRUE(client().has_received_completion());
   EXPECT_EQ(net::OK, client().completion_status().error_code);
 }
@@ -1303,7 +1303,7 @@
   EXPECT_TRUE(client().has_received_redirect());
   EXPECT_TRUE(client().has_received_response());
   EXPECT_EQ(network::mojom::FetchResponseType::kBasic,
-            client().response_head().response_type);
+            client().response_head()->response_type);
   EXPECT_TRUE(client().has_received_completion());
   EXPECT_EQ(net::OK, client().completion_status().error_code);
 }
@@ -1355,7 +1355,7 @@
   EXPECT_FALSE(client().has_received_redirect());
   EXPECT_TRUE(client().has_received_response());
   EXPECT_EQ(network::mojom::FetchResponseType::kBasic,
-            client().response_head().response_type);
+            client().response_head()->response_type);
   EXPECT_TRUE(client().has_received_completion());
   EXPECT_EQ(net::OK, client().completion_status().error_code);
 }
@@ -1407,7 +1407,7 @@
   EXPECT_FALSE(client().has_received_redirect());
   EXPECT_TRUE(client().has_received_response());
   EXPECT_EQ(network::mojom::FetchResponseType::kBasic,
-            client().response_head().response_type);
+            client().response_head()->response_type);
   EXPECT_TRUE(client().has_received_completion());
   EXPECT_EQ(net::OK, client().completion_status().error_code);
 }
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc
index e3e8fff1..8b37289 100644
--- a/services/network/network_context_unittest.cc
+++ b/services/network/network_context_unittest.cc
@@ -2662,10 +2662,10 @@
 };
 
 TEST_F(NetworkContextTest, ResolveHost_Sync) {
+  auto resolver = std::make_unique<net::MockHostResolver>();
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(CreateContextParams());
 
-  auto resolver = std::make_unique<net::MockHostResolver>();
   network_context->url_request_context()->set_host_resolver(resolver.get());
   resolver->set_synchronous_mode(true);
 
@@ -2691,10 +2691,10 @@
 }
 
 TEST_F(NetworkContextTest, ResolveHost_Async) {
+  auto resolver = std::make_unique<net::MockHostResolver>();
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(CreateContextParams());
 
-  auto resolver = std::make_unique<net::MockHostResolver>();
   network_context->url_request_context()->set_host_resolver(resolver.get());
   resolver->set_synchronous_mode(false);
 
@@ -2726,10 +2726,10 @@
 }
 
 TEST_F(NetworkContextTest, ResolveHost_Failure_Sync) {
+  auto resolver = std::make_unique<net::MockHostResolver>();
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(CreateContextParams());
 
-  auto resolver = std::make_unique<net::MockHostResolver>();
   network_context->url_request_context()->set_host_resolver(resolver.get());
   resolver->rules()->AddSimulatedFailure("example.com");
   resolver->set_synchronous_mode(true);
@@ -2754,10 +2754,10 @@
 }
 
 TEST_F(NetworkContextTest, ResolveHost_Failure_Async) {
+  auto resolver = std::make_unique<net::MockHostResolver>();
   std::unique_ptr<NetworkContext> network_context =
       CreateContextWithParams(CreateContextParams());
 
-  auto resolver = std::make_unique<net::MockHostResolver>();
   network_context->url_request_context()->set_host_resolver(resolver.get());
   resolver->rules()->AddSimulatedFailure("example.com");
   resolver->set_synchronous_mode(false);
@@ -2840,12 +2840,11 @@
 }
 
 TEST_F(NetworkContextTest, ResolveHost_Cancellation) {
-  std::unique_ptr<NetworkContext> network_context =
-      CreateContextWithParams(CreateContextParams());
-
   // Override the HostResolver with a hanging one, so the test can ensure the
   // request won't be completed before the cancellation arrives.
   auto resolver = std::make_unique<net::HangingHostResolver>();
+  std::unique_ptr<NetworkContext> network_context =
+      CreateContextWithParams(CreateContextParams());
   network_context->url_request_context()->set_host_resolver(resolver.get());
 
   ASSERT_EQ(0, resolver->num_cancellations());
@@ -2880,12 +2879,11 @@
 }
 
 TEST_F(NetworkContextTest, ResolveHost_DestroyContext) {
-  std::unique_ptr<NetworkContext> network_context =
-      CreateContextWithParams(CreateContextParams());
-
   // Override the HostResolver with a hanging one, so the test can ensure the
   // request won't be completed before the cancellation arrives.
   auto resolver = std::make_unique<net::HangingHostResolver>();
+  std::unique_ptr<NetworkContext> network_context =
+      CreateContextWithParams(CreateContextParams());
   network_context->url_request_context()->set_host_resolver(resolver.get());
 
   ASSERT_EQ(0, resolver->num_cancellations());
@@ -2918,12 +2916,11 @@
 }
 
 TEST_F(NetworkContextTest, ResolveHost_CloseClient) {
-  std::unique_ptr<NetworkContext> network_context =
-      CreateContextWithParams(CreateContextParams());
-
   // Override the HostResolver with a hanging one, so the test can ensure the
   // request won't be completed before the cancellation arrives.
   auto resolver = std::make_unique<net::HangingHostResolver>();
+  std::unique_ptr<NetworkContext> network_context =
+      CreateContextWithParams(CreateContextParams());
   network_context->url_request_context()->set_host_resolver(resolver.get());
 
   ASSERT_EQ(0, resolver->num_cancellations());
@@ -3038,12 +3035,11 @@
 }
 
 TEST_F(NetworkContextTest, CreateHostResolver_CloseResolver) {
-  std::unique_ptr<NetworkContext> network_context =
-      CreateContextWithParams(CreateContextParams());
-
   // Override the HostResolver with a hanging one, so the test can ensure the
   // request won't be completed before the cancellation arrives.
   auto internal_resolver = std::make_unique<net::HangingHostResolver>();
+  std::unique_ptr<NetworkContext> network_context =
+      CreateContextWithParams(CreateContextParams());
   network_context->url_request_context()->set_host_resolver(
       internal_resolver.get());
 
@@ -3081,12 +3077,11 @@
 }
 
 TEST_F(NetworkContextTest, CreateHostResolver_CloseContext) {
-  std::unique_ptr<NetworkContext> network_context =
-      CreateContextWithParams(CreateContextParams());
-
   // Override the HostResolver with a hanging one, so the test can ensure the
   // request won't be completed before the cancellation arrives.
   auto internal_resolver = std::make_unique<net::HangingHostResolver>();
+  std::unique_ptr<NetworkContext> network_context =
+      CreateContextWithParams(CreateContextParams());
   network_context->url_request_context()->set_host_resolver(
       internal_resolver.get());
 
@@ -4497,7 +4492,7 @@
     client.RunUntilComplete();
 
     EXPECT_TRUE(client.has_received_completion());
-    EXPECT_EQ(client.response_head().proxy_server.scheme(),
+    EXPECT_EQ(client.response_head()->proxy_server.scheme(),
               proxy_data.expected_proxy_config_scheme);
   }
 }
@@ -4615,7 +4610,7 @@
     EXPECT_EQ(response, "bar");
 
     // Make sure response header was modified.
-    EXPECT_TRUE(client.response_head().headers->HasHeaderValue("baz", "qux"));
+    EXPECT_TRUE(client.response_head()->headers->HasHeaderValue("baz", "qux"));
   }
 
   // Next, do a request without kURLLoadOptionUseHeaderClient set, headers
@@ -4637,7 +4632,7 @@
     EXPECT_EQ(response, "None");
 
     // Make sure response header was not set.
-    EXPECT_FALSE(client.response_head().headers->HasHeaderValue("foo", "bar"));
+    EXPECT_FALSE(client.response_head()->headers->HasHeaderValue("foo", "bar"));
   }
 }
 
@@ -4835,7 +4830,7 @@
   EXPECT_EQ(response, "bar");
 
   // Make sure response header was modified.
-  EXPECT_TRUE(client.response_head().headers->HasHeaderValue("baz", "qux"));
+  EXPECT_TRUE(client.response_head()->headers->HasHeaderValue("baz", "qux"));
 }
 
 // Test destroying the mojom::URLLoader after the OnBeforeSendHeaders event and
@@ -5015,7 +5010,7 @@
   EXPECT_EQ(response, base::JoinString({"post_bar_value", "post_foo_value",
                                         "pre_bar_value", "pre_foo_value"},
                                        "\n"));
-  EXPECT_EQ(client->response_head().proxy_server, proxy_server);
+  EXPECT_EQ(client->response_head()->proxy_server, proxy_server);
 }
 
 // Tests that if using a custom proxy results in redirect loop, then
@@ -5155,7 +5150,7 @@
             base::JoinString({"first_bar_key=value2, bar_next_key=value4",
                               "first_foo_key=value1, foo_next_key=value3"},
                              "\n"));
-  EXPECT_EQ(client->response_head().proxy_server, proxy_server);
+  EXPECT_EQ(client->response_head()->proxy_server, proxy_server);
 }
 
 TEST_F(NetworkContextMockHostTest, CustomProxyConfigHeadersAddedBeforeCache) {
@@ -5191,8 +5186,8 @@
       mojo::BlockingCopyToString(client->response_body_release(), &response));
 
   EXPECT_EQ(response, base::JoinString({"bar_value", "foo_value"}, "\n"));
-  EXPECT_EQ(client->response_head().proxy_server, proxy_server);
-  EXPECT_FALSE(client->response_head().was_fetched_via_cache);
+  EXPECT_EQ(client->response_head()->proxy_server, proxy_server);
+  EXPECT_FALSE(client->response_head()->was_fetched_via_cache);
 
   // post_cache_headers should not break caching.
   config->post_cache_headers.SetHeader("bar", "new_bar");
@@ -5204,7 +5199,7 @@
       mojo::BlockingCopyToString(client->response_body_release(), &response));
 
   EXPECT_EQ(response, base::JoinString({"bar_value", "foo_value"}, "\n"));
-  EXPECT_TRUE(client->response_head().was_fetched_via_cache);
+  EXPECT_TRUE(client->response_head()->was_fetched_via_cache);
 
   // pre_cache_headers should invalidate cache.
   config->pre_cache_headers.SetHeader("foo", "new_foo");
@@ -5216,8 +5211,8 @@
       mojo::BlockingCopyToString(client->response_body_release(), &response));
 
   EXPECT_EQ(response, base::JoinString({"new_bar", "new_foo"}, "\n"));
-  EXPECT_EQ(client->response_head().proxy_server, proxy_server);
-  EXPECT_FALSE(client->response_head().was_fetched_via_cache);
+  EXPECT_EQ(client->response_head()->proxy_server, proxy_server);
+  EXPECT_FALSE(client->response_head()->was_fetched_via_cache);
 }
 
 TEST_F(NetworkContextMockHostTest, CustomProxyRequestHeadersAddedBeforeCache) {
@@ -5253,8 +5248,8 @@
       mojo::BlockingCopyToString(client->response_body_release(), &response));
 
   EXPECT_EQ(response, base::JoinString({"bar_value", "foo_value"}, "\n"));
-  EXPECT_EQ(client->response_head().proxy_server, proxy_server);
-  EXPECT_FALSE(client->response_head().was_fetched_via_cache);
+  EXPECT_EQ(client->response_head()->proxy_server, proxy_server);
+  EXPECT_FALSE(client->response_head()->was_fetched_via_cache);
 
   // custom_proxy_post_cache_headers should not break caching.
   request.custom_proxy_post_cache_headers.SetHeader("bar", "new_bar");
@@ -5264,7 +5259,7 @@
       mojo::BlockingCopyToString(client->response_body_release(), &response));
 
   EXPECT_EQ(response, base::JoinString({"bar_value", "foo_value"}, "\n"));
-  EXPECT_TRUE(client->response_head().was_fetched_via_cache);
+  EXPECT_TRUE(client->response_head()->was_fetched_via_cache);
 
   // custom_proxy_pre_cache_headers should invalidate cache.
   request.custom_proxy_pre_cache_headers.SetHeader("foo", "new_foo");
@@ -5274,8 +5269,8 @@
       mojo::BlockingCopyToString(client->response_body_release(), &response));
 
   EXPECT_EQ(response, base::JoinString({"new_bar", "new_foo"}, "\n"));
-  EXPECT_EQ(client->response_head().proxy_server, proxy_server);
-  EXPECT_FALSE(client->response_head().was_fetched_via_cache);
+  EXPECT_EQ(client->response_head()->proxy_server, proxy_server);
+  EXPECT_FALSE(client->response_head()->was_fetched_via_cache);
 }
 
 TEST_F(NetworkContextMockHostTest,
@@ -5311,7 +5306,7 @@
       mojo::BlockingCopyToString(client->response_body_release(), &response));
 
   EXPECT_EQ(response, base::JoinString({"None", "None", "None", "None"}, "\n"));
-  EXPECT_TRUE(client->response_head().proxy_server.is_direct());
+  EXPECT_TRUE(client->response_head()->proxy_server.is_direct());
 }
 
 TEST_F(NetworkContextMockHostTest,
@@ -5356,7 +5351,7 @@
       mojo::BlockingCopyToString(client->response_body_release(), &response));
 
   EXPECT_EQ(response, base::JoinString({"None", "None", "None", "None"}, "\n"));
-  EXPECT_EQ(client->response_head().proxy_server,
+  EXPECT_EQ(client->response_head()->proxy_server,
             ConvertToProxyServer(proxy_test_server));
 }
 
@@ -5389,7 +5384,7 @@
 
   // |invalid_server| has no handlers set up so would return an empty response.
   EXPECT_EQ(response, "Echo");
-  EXPECT_EQ(client->response_head().proxy_server,
+  EXPECT_EQ(client->response_head()->proxy_server,
             ConvertToProxyServer(proxy_test_server));
 }
 
diff --git a/services/network/network_service_unittest.cc b/services/network/network_service_unittest.cc
index 050cfe3b..7e75db4 100644
--- a/services/network/network_service_unittest.cc
+++ b/services/network/network_service_unittest.cc
@@ -842,10 +842,10 @@
   StartLoadingURL(request, 0);
   client()->RunUntilRedirectReceived();
   EXPECT_TRUE(client()->has_received_redirect());
-  EXPECT_TRUE(!client()->response_head().raw_request_response_info);
+  EXPECT_TRUE(!client()->response_head()->raw_request_response_info);
   loader()->FollowRedirect({}, {}, base::nullopt);
   client()->RunUntilComplete();
-  EXPECT_TRUE(!client()->response_head().raw_request_response_info);
+  EXPECT_TRUE(!client()->response_head()->raw_request_response_info);
 }
 
 TEST_F(NetworkServiceTestWithService, RawRequestHeadersPresent) {
@@ -859,8 +859,8 @@
   client()->RunUntilRedirectReceived();
   EXPECT_TRUE(client()->has_received_redirect());
   {
-    scoped_refptr<HttpRawRequestResponseInfo> request_response_info =
-        client()->response_head().raw_request_response_info;
+    auto& request_response_info =
+        client()->response_head()->raw_request_response_info;
     ASSERT_TRUE(request_response_info);
     EXPECT_EQ(301, request_response_info->http_status_code);
     EXPECT_EQ("Moved Permanently", request_response_info->http_status_text);
@@ -876,8 +876,8 @@
   loader()->FollowRedirect({}, {}, base::nullopt);
   client()->RunUntilComplete();
   {
-    scoped_refptr<HttpRawRequestResponseInfo> request_response_info =
-        client()->response_head().raw_request_response_info;
+    auto& request_response_info =
+        client()->response_head()->raw_request_response_info;
     EXPECT_EQ(200, request_response_info->http_status_code);
     EXPECT_EQ("OK", request_response_info->http_status_text);
     EXPECT_TRUE(base::StartsWith(request_response_info->request_headers_text,
@@ -902,7 +902,7 @@
 
   StartLoadingURL(request, process_id);
   client()->RunUntilComplete();
-  EXPECT_FALSE(client()->response_head().raw_request_response_info);
+  EXPECT_FALSE(client()->response_head()->raw_request_response_info);
   service()->SetRawHeadersAccess(
       process_id,
       {url::Origin::CreateFromNormalizedTuple("http", "example.com", 80),
@@ -910,8 +910,8 @@
   StartLoadingURL(request, process_id);
   client()->RunUntilComplete();
   {
-    scoped_refptr<HttpRawRequestResponseInfo> request_response_info =
-        client()->response_head().raw_request_response_info;
+    auto& request_response_info =
+        client()->response_head()->raw_request_response_info;
     ASSERT_TRUE(request_response_info);
     EXPECT_EQ(200, request_response_info->http_status_code);
     EXPECT_EQ("OK", request_response_info->http_status_text);
@@ -920,14 +920,14 @@
   service()->SetRawHeadersAccess(process_id, {});
   StartLoadingURL(request, process_id);
   client()->RunUntilComplete();
-  EXPECT_FALSE(client()->response_head().raw_request_response_info.get());
+  EXPECT_FALSE(client()->response_head()->raw_request_response_info.get());
 
   service()->SetRawHeadersAccess(
       process_id,
       {url::Origin::CreateFromNormalizedTuple("http", "example.com", 80)});
   StartLoadingURL(request, process_id);
   client()->RunUntilComplete();
-  EXPECT_FALSE(client()->response_head().raw_request_response_info.get());
+  EXPECT_FALSE(client()->response_head()->raw_request_response_info.get());
 }
 
 class NetworkServiceTestWithResolverMap : public NetworkServiceTestWithService {
@@ -959,31 +959,31 @@
 
   StartLoadingURL(request, process_id);
   client()->RunUntilRedirectReceived();  // from a.test to b.test
-  EXPECT_TRUE(client()->response_head().raw_request_response_info);
+  EXPECT_TRUE(client()->response_head()->raw_request_response_info);
 
   loader()->FollowRedirect({}, {}, base::nullopt);
   client()->ClearHasReceivedRedirect();
   client()->RunUntilRedirectReceived();  // from b.test to a.test
-  EXPECT_FALSE(client()->response_head().raw_request_response_info);
+  EXPECT_FALSE(client()->response_head()->raw_request_response_info);
 
   loader()->FollowRedirect({}, {}, base::nullopt);
   client()->RunUntilComplete();  // Done loading a.test
-  EXPECT_TRUE(client()->response_head().raw_request_response_info.get());
+  EXPECT_TRUE(client()->response_head()->raw_request_response_info.get());
 
   service()->SetRawHeadersAccess(process_id, {url::Origin::Create(url_b)});
 
   StartLoadingURL(request, process_id);
   client()->RunUntilRedirectReceived();  // from a.test to b.test
-  EXPECT_FALSE(client()->response_head().raw_request_response_info);
+  EXPECT_FALSE(client()->response_head()->raw_request_response_info);
 
   loader()->FollowRedirect({}, {}, base::nullopt);
   client()->ClearHasReceivedRedirect();
   client()->RunUntilRedirectReceived();  // from b.test to a.test
-  EXPECT_TRUE(client()->response_head().raw_request_response_info);
+  EXPECT_TRUE(client()->response_head()->raw_request_response_info);
 
   loader()->FollowRedirect({}, {}, base::nullopt);
   client()->RunUntilComplete();  // Done loading a.test
-  EXPECT_FALSE(client()->response_head().raw_request_response_info.get());
+  EXPECT_FALSE(client()->response_head()->raw_request_response_info.get());
 }
 
 TEST_F(NetworkServiceTestWithService, SetNetworkConditions) {
@@ -1247,7 +1247,7 @@
           mojom::kURLLoadOptionSendSSLInfoWithResponse);
   EXPECT_EQ(net::OK, client()->completion_status().error_code);
   EXPECT_EQ(
-      0u, client()->response_head().cert_status & net::CERT_STATUS_ALL_ERRORS);
+      0u, client()->response_head()->cert_status & net::CERT_STATUS_ALL_ERRORS);
   ASSERT_TRUE(client()->ssl_info());
   ASSERT_TRUE(client()->ssl_info()->cert);
   EXPECT_EQ(2u, client()->ssl_info()->cert->intermediate_buffers().size());
diff --git a/services/network/public/cpp/content_security_policy.h b/services/network/public/cpp/content_security_policy.h
index aff9540..4d5f467f 100644
--- a/services/network/public/cpp/content_security_policy.h
+++ b/services/network/public/cpp/content_security_policy.h
@@ -34,6 +34,9 @@
   // Parses the Content-Security-Policy headers specified in |headers|.
   bool Parse(const net::HttpResponseHeaders& headers);
 
+  // Parses a Content-Security-Policy |header|.
+  bool Parse(base::StringPiece header);
+
   const mojom::ContentSecurityPolicyPtr& content_security_policy_ptr() {
     return content_security_policy_ptr_;
   }
@@ -42,8 +45,6 @@
   }
 
  private:
-  friend int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
-  bool Parse(base::StringPiece header);
 
   // Parses the frame-ancestor directive of a Content-Security-Policy header.
   bool ParseFrameAncestors(base::StringPiece header_value);
diff --git a/services/network/public/mojom/url_loader.mojom b/services/network/public/mojom/url_loader.mojom
index 0a26de6b..9559c14 100644
--- a/services/network/public/mojom/url_loader.mojom
+++ b/services/network/public/mojom/url_loader.mojom
@@ -253,11 +253,10 @@
   //   created by a frame.
   // - MSG_ROUTING_NONE for nested dedicated workers.
   // - MSG_ROUTING_NONE for subresource requests from a dedicated/shared worker.
+  // - service_worker_route_id from EmbeddedWorkerStartParams for service worker
+  //   main script requests and subresource requests.
   // - The frame tree node ID for navigation requests only. Please do not use
   //   frame tree node ID for other requests.
-  // TODO(nhiroki): Clarify which frame id should be used for service workers.
-  // Probably the render frame id of the frame calling register() or update(),
-  // and MSG_ROUTING_NONE for the soft update.
   int32 render_frame_id;
 
   // True if |frame_id| is the main frame of a RenderView.
diff --git a/services/network/test/test_url_loader_client.cc b/services/network/test/test_url_loader_client.cc
index f267ba8..a3d8035 100644
--- a/services/network/test/test_url_loader_client.cc
+++ b/services/network/test/test_url_loader_client.cc
@@ -7,6 +7,7 @@
 #include "base/bind.h"
 #include "base/memory/ref_counted.h"
 #include "base/run_loop.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace network {
@@ -20,7 +21,7 @@
   EXPECT_FALSE(has_received_cached_metadata_);
   EXPECT_FALSE(has_received_completion_);
   has_received_response_ = true;
-  response_head_ = response_head;
+  response_head_ = std::move(response_head);
   if (quit_closure_for_on_receive_response_)
     std::move(quit_closure_for_on_receive_response_).Run();
 }
@@ -36,7 +37,7 @@
   EXPECT_FALSE(has_received_completion_);
   has_received_redirect_ = true;
   redirect_info_ = redirect_info;
-  response_head_ = response_head;
+  response_head_ = std::move(response_head);
   if (quit_closure_for_on_receive_redirect_)
     std::move(quit_closure_for_on_receive_redirect_).Run();
 }
diff --git a/services/network/test/test_url_loader_client.h b/services/network/test/test_url_loader_client.h
index 74a8087..284faea 100644
--- a/services/network/test/test_url_loader_client.h
+++ b/services/network/test/test_url_loader_client.h
@@ -13,10 +13,10 @@
 #include "mojo/public/c/system/data_pipe.h"
 #include "mojo/public/cpp/bindings/binding.h"
 #include "net/url_request/redirect_info.h"
-#include "services/network/public/cpp/resource_response.h"
 #include "services/network/public/cpp/url_loader_completion_status.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "services/network/public/mojom/url_response_head.mojom-forward.h"
 
 namespace network {
 
@@ -57,9 +57,12 @@
   bool has_received_connection_error() const {
     return has_received_connection_error_;
   }
-  const ResourceResponseHead& response_head() const { return response_head_; }
+  const mojom::URLResponseHeadPtr& response_head() const {
+    return response_head_;
+  }
   const base::Optional<net::SSLInfo>& ssl_info() const {
-    return response_head_.ssl_info;
+    DCHECK(response_head_);
+    return response_head_->ssl_info;
   }
   const net::RedirectInfo& redirect_info() const { return redirect_info_; }
   const std::string& cached_metadata() const { return cached_metadata_; }
@@ -96,7 +99,7 @@
   void OnConnectionError();
 
   mojo::Binding<mojom::URLLoaderClient> binding_;
-  ResourceResponseHead response_head_;
+  mojom::URLResponseHeadPtr response_head_;
   net::RedirectInfo redirect_info_;
   std::string cached_metadata_;
   mojo::ScopedDataPipeConsumerHandle response_body_;
diff --git a/services/network/test/test_url_loader_factory.cc b/services/network/test/test_url_loader_factory.cc
index ad3cca53..1187ca1e 100644
--- a/services/network/test/test_url_loader_factory.cc
+++ b/services/network/test/test_url_loader_factory.cc
@@ -12,6 +12,7 @@
 #include "services/network/public/cpp/resource_request_body.h"
 #include "services/network/public/cpp/weak_wrapper_shared_url_loader_factory.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 #include "services/network/test/test_utils.h"
 
 namespace network {
@@ -26,7 +27,9 @@
 
 TestURLLoaderFactory::Response::Response() = default;
 TestURLLoaderFactory::Response::~Response() = default;
-TestURLLoaderFactory::Response::Response(const Response&) = default;
+TestURLLoaderFactory::Response::Response(Response&&) = default;
+TestURLLoaderFactory::Response& TestURLLoaderFactory::Response::operator=(
+    Response&&) = default;
 
 TestURLLoaderFactory::TestURLLoaderFactory()
     : weak_wrapper_(
@@ -38,20 +41,20 @@
 }
 
 void TestURLLoaderFactory::AddResponse(const GURL& url,
-                                       const ResourceResponseHead& head,
+                                       mojom::URLResponseHeadPtr head,
                                        const std::string& content,
                                        const URLLoaderCompletionStatus& status,
-                                       const Redirects& redirects,
+                                       Redirects redirects,
                                        ResponseProduceFlags flags) {
   Response response;
   response.url = url;
-  response.redirects = redirects;
-  response.head = head;
+  response.redirects = std::move(redirects);
+  response.head = std::move(head);
   response.content = content;
   response.status = status;
   response.status.decoded_body_length = content.size();
   response.flags = flags;
-  responses_[url] = response;
+  responses_[url] = std::move(response);
 
   for (auto it = pending_requests_.begin(); it != pending_requests_.end();) {
     if (CreateLoaderAndStartInternal(it->request.url, it->client.get())) {
@@ -65,10 +68,10 @@
 void TestURLLoaderFactory::AddResponse(const std::string& url,
                                        const std::string& content,
                                        net::HttpStatusCode http_status) {
-  ResourceResponseHead head = CreateResourceResponseHead(http_status);
-  head.mime_type = "text/html";
+  mojom::URLResponseHeadPtr head = CreateURLResponseHead(http_status);
+  head->mime_type = "text/html";
   URLLoaderCompletionStatus status;
-  AddResponse(GURL(url), head, content, status);
+  AddResponse(GURL(url), std::move(head), content, status);
 }
 
 bool TestURLLoaderFactory::IsPending(const std::string& url,
@@ -148,7 +151,12 @@
   if (it == responses_.end())
     return false;
 
-  SimulateResponse(client, it->second.redirects, it->second.head,
+  Redirects redirects;
+  for (auto& redirect : it->second.redirects) {
+    redirects.push_back(
+        std::make_pair(redirect.first, redirect.second.Clone()));
+  }
+  SimulateResponse(client, std::move(redirects), it->second.head.Clone(),
                    it->second.content, it->second.status, it->second.flags);
   return true;
 }
@@ -156,7 +164,7 @@
 bool TestURLLoaderFactory::SimulateResponseForPendingRequest(
     const GURL& url,
     const network::URLLoaderCompletionStatus& completion_status,
-    const ResourceResponseHead& response_head,
+    mojom::URLResponseHeadPtr response_head,
     const std::string& content,
     ResponseMatchFlags flags) {
   if (pending_requests_.empty())
@@ -196,7 +204,7 @@
   status.decoded_body_length = content.size();
 
   SimulateResponse(request.client.get(), TestURLLoaderFactory::Redirects(),
-                   response_head, content, status, kResponseDefault);
+                   std::move(response_head), content, status, kResponseDefault);
   base::RunLoop().RunUntilIdle();
 
   return true;
@@ -207,23 +215,23 @@
     const std::string& content,
     net::HttpStatusCode http_status,
     ResponseMatchFlags flags) {
-  ResourceResponseHead head = CreateResourceResponseHead(http_status);
-  head.mime_type = "text/html";
+  mojom::URLResponseHeadPtr head = CreateURLResponseHead(http_status);
+  head->mime_type = "text/html";
   URLLoaderCompletionStatus status;
   status.decoded_body_length = content.size();
-  return SimulateResponseForPendingRequest(GURL(url), status, head, content,
-                                           flags);
+  return SimulateResponseForPendingRequest(GURL(url), status, std::move(head),
+                                           content, flags);
 }
 
 void TestURLLoaderFactory::SimulateResponseWithoutRemovingFromPendingList(
     PendingRequest* request,
-    const ResourceResponseHead& head,
+    mojom::URLResponseHeadPtr head,
     std::string content,
     const URLLoaderCompletionStatus& completion_status) {
   URLLoaderCompletionStatus status(completion_status);
   status.decoded_body_length = content.size();
   SimulateResponse(request->client.get(), TestURLLoaderFactory::Redirects(),
-                   head, content, status, kResponseDefault);
+                   std::move(head), content, status, kResponseDefault);
   base::RunLoop().RunUntilIdle();
 }
 
@@ -231,28 +239,28 @@
     PendingRequest* request,
     std::string content) {
   URLLoaderCompletionStatus completion_status(net::OK);
-  ResourceResponseHead head = CreateResourceResponseHead(net::HTTP_OK);
-  SimulateResponseWithoutRemovingFromPendingList(request, head, content,
-                                                 completion_status);
+  mojom::URLResponseHeadPtr head = CreateURLResponseHead(net::HTTP_OK);
+  SimulateResponseWithoutRemovingFromPendingList(request, std::move(head),
+                                                 content, completion_status);
 }
 
 // static
 void TestURLLoaderFactory::SimulateResponse(
     mojom::URLLoaderClient* client,
     TestURLLoaderFactory::Redirects redirects,
-    ResourceResponseHead head,
+    mojom::URLResponseHeadPtr head,
     std::string content,
     URLLoaderCompletionStatus status,
     ResponseProduceFlags response_flags) {
   for (const auto& redirect : redirects)
-    client->OnReceiveRedirect(redirect.first, redirect.second);
+    client->OnReceiveRedirect(redirect.first, redirect.second.Clone());
 
   if (response_flags & kResponseOnlyRedirectsNoDestination)
     return;
 
   if ((response_flags & kSendHeadersOnNetworkError) ||
       status.error_code == net::OK) {
-    client->OnReceiveResponse(head);
+    client->OnReceiveResponse(std::move(head));
   }
 
   if (status.error_code == net::OK) {
diff --git a/services/network/test/test_url_loader_factory.h b/services/network/test/test_url_loader_factory.h
index f6e3319..bab4f6e 100644
--- a/services/network/test/test_url_loader_factory.h
+++ b/services/network/test/test_url_loader_factory.h
@@ -14,9 +14,9 @@
 #include "mojo/public/cpp/bindings/binding_set.h"
 #include "net/http/http_status_code.h"
 #include "services/network/public/cpp/resource_request.h"
-#include "services/network/public/cpp/resource_response.h"
 #include "services/network/public/mojom/url_loader.mojom.h"
 #include "services/network/public/mojom/url_loader_factory.mojom.h"
+#include "services/network/public/mojom/url_response_head.mojom-forward.h"
 
 namespace network {
 class WeakWrapperSharedURLLoaderFactory;
@@ -58,7 +58,7 @@
   ~TestURLLoaderFactory() override;
 
   using Redirects =
-      std::vector<std::pair<net::RedirectInfo, ResourceResponseHead>>;
+      std::vector<std::pair<net::RedirectInfo, mojom::URLResponseHeadPtr>>;
 
   // Adds a response to be served. There is one unique response per URL, and if
   // this method is called multiple times for the same URL the last response
@@ -66,10 +66,10 @@
   // This can be called before or after a request is made. If it's called after,
   // then pending requests will be "woken up".
   void AddResponse(const GURL& url,
-                   const ResourceResponseHead& head,
+                   mojom::URLResponseHeadPtr head,
                    const std::string& content,
                    const URLLoaderCompletionStatus& status,
-                   const Redirects& redirects = Redirects(),
+                   Redirects redirects = Redirects(),
                    ResponseProduceFlags rp_flags = kResponseDefault);
 
   // Simpler version of above for the common case of success or error page.
@@ -113,7 +113,7 @@
   bool SimulateResponseForPendingRequest(
       const GURL& url,
       const network::URLLoaderCompletionStatus& completion_status,
-      const ResourceResponseHead& response_head,
+      mojom::URLResponseHeadPtr response_head,
       const std::string& content,
       ResponseMatchFlags flags = kMatchDefault);
 
@@ -132,7 +132,7 @@
   // This method is useful to process requests at a given pre-defined order.
   void SimulateResponseWithoutRemovingFromPendingList(
       PendingRequest* request,
-      const ResourceResponseHead& head,
+      mojom::URLResponseHeadPtr head,
       std::string content,
       const URLLoaderCompletionStatus& status);
 
@@ -170,7 +170,7 @@
 
   static void SimulateResponse(mojom::URLLoaderClient* client,
                                Redirects redirects,
-                               ResourceResponseHead head,
+                               mojom::URLResponseHeadPtr head,
                                std::string content,
                                URLLoaderCompletionStatus status,
                                ResponseProduceFlags response_flags);
@@ -178,10 +178,11 @@
   struct Response {
     Response();
     ~Response();
-    Response(const Response&);
+    Response(Response&&);
+    Response& operator=(Response&&);
     GURL url;
     Redirects redirects;
-    ResourceResponseHead head;
+    mojom::URLResponseHeadPtr head;
     std::string content;
     URLLoaderCompletionStatus status;
     ResponseProduceFlags flags;
diff --git a/services/network/test/test_url_loader_factory_unittest.cc b/services/network/test/test_url_loader_factory_unittest.cc
index 0749c9b..76e73279 100644
--- a/services/network/test/test_url_loader_factory_unittest.cc
+++ b/services/network/test/test_url_loader_factory_unittest.cc
@@ -81,12 +81,12 @@
   std::string body = "Happy robot";
 
   // Test the full-featured version of AddResponse.
-  factory()->AddResponse(GURL(url), CreateResourceResponseHead(net::HTTP_OK),
-                         body, URLLoaderCompletionStatus(net::OK));
+  factory()->AddResponse(GURL(url), CreateURLResponseHead(net::HTTP_OK), body,
+                         URLLoaderCompletionStatus(net::OK));
   StartRequest(url);
   client()->RunUntilComplete();
-  ASSERT_TRUE(client()->response_head().headers != nullptr);
-  EXPECT_EQ(net::HTTP_OK, client()->response_head().headers->response_code());
+  ASSERT_TRUE(client()->response_head()->headers != nullptr);
+  EXPECT_EQ(net::HTTP_OK, client()->response_head()->headers->response_code());
   EXPECT_EQ(body, GetData(client()));
 }
 
@@ -97,9 +97,9 @@
 
   StartRequest(url);
   client()->RunUntilComplete();
-  ASSERT_TRUE(client()->response_head().headers != nullptr);
+  ASSERT_TRUE(client()->response_head()->headers != nullptr);
   EXPECT_EQ(net::HTTP_NOT_FOUND,
-            client()->response_head().headers->response_code());
+            client()->response_head()->headers->response_code());
   EXPECT_EQ(GetData(client()), body);
 }
 
@@ -139,12 +139,12 @@
   net::RedirectInfo redirect_info;
   redirect_info.status_code = 301;
   redirect_info.new_url = GURL("http://example2.test/");
-  TestURLLoaderFactory::Redirects redirects{
-      {redirect_info, ResourceResponseHead()}};
+  TestURLLoaderFactory::Redirects redirects;
+  redirects.push_back({redirect_info, mojom::URLResponseHead::New()});
   URLLoaderCompletionStatus status;
   std::string content = "foo";
-  factory()->AddResponse(url, ResourceResponseHead(), content, status,
-                         redirects);
+  factory()->AddResponse(url, mojom::URLResponseHead::New(), content, status,
+                         std::move(redirects));
   StartRequest(url.spec());
   client()->RunUntilComplete();
 
@@ -232,32 +232,32 @@
 TEST_F(TestURLLoaderFactoryTest, SimulateResponse) {
   std::string url = "http://foo/";
   network::URLLoaderCompletionStatus ok_status(net::OK);
-  ResourceResponseHead response_head =
-      CreateResourceResponseHead(net::HTTP_NOT_FOUND);
-  response_head.headers->AddHeader("Foo: Bar");
+  mojom::URLResponseHeadPtr response_head =
+      CreateURLResponseHead(net::HTTP_NOT_FOUND);
+  response_head->headers->AddHeader("Foo: Bar");
 
   // By default no request is pending.
   EXPECT_FALSE(factory()->SimulateResponseForPendingRequest(
-      GURL(url), ok_status, response_head, /*content=*/""));
+      GURL(url), ok_status, response_head.Clone(), /*content=*/""));
 
   StartRequest(url);
   EXPECT_EQ(1, factory()->NumPending());
   // Try with the wrong URL
   EXPECT_FALSE(factory()->SimulateResponseForPendingRequest(
       GURL("http://this_is_not_the_url_you_are_looking_for"), ok_status,
-      response_head, /*content=*/""));
+      response_head.Clone(), /*content=*/""));
   EXPECT_TRUE(factory()->SimulateResponseForPendingRequest(
-      GURL(url), ok_status, response_head, /*content=*/"hello"));
+      GURL(url), ok_status, response_head.Clone(), /*content=*/"hello"));
   EXPECT_EQ(0, factory()->NumPending());
   EXPECT_TRUE(client()->has_received_completion());
   EXPECT_EQ(net::OK, client()->completion_status().error_code);
-  ASSERT_TRUE(client()->response_head().headers);
+  ASSERT_TRUE(client()->response_head()->headers);
   EXPECT_EQ(net::HTTP_NOT_FOUND,
-            client()->response_head().headers->response_code());
+            client()->response_head()->headers->response_code());
   // Our header should be set.
   std::string value;
   EXPECT_TRUE(
-      client()->response_head().headers->GetNormalizedHeader("Foo", &value));
+      client()->response_head()->headers->GetNormalizedHeader("Foo", &value));
   EXPECT_EQ("Bar", value);
   std::string response;
   EXPECT_TRUE(
@@ -274,15 +274,15 @@
   StartRequest(url, &client2);
 
   network::URLLoaderCompletionStatus ok_status(net::OK);
-  ResourceResponseHead response_head = CreateResourceResponseHead(net::HTTP_OK);
+  mojom::URLResponseHeadPtr response_head = CreateURLResponseHead(net::HTTP_OK);
 
   EXPECT_EQ(2, factory()->NumPending());
   EXPECT_TRUE(factory()->SimulateResponseForPendingRequest(
-      GURL(url), ok_status, response_head, /*content=*/""));
+      GURL(url), ok_status, response_head.Clone(), /*content=*/""));
   EXPECT_EQ(1, factory()->NumPending());
   EXPECT_TRUE(client1.has_received_completion());
   EXPECT_TRUE(factory()->SimulateResponseForPendingRequest(
-      GURL(url), ok_status, response_head, /*content=*/""));
+      GURL(url), ok_status, response_head.Clone(), /*content=*/""));
   EXPECT_EQ(0, factory()->NumPending());
   EXPECT_TRUE(client2.has_received_completion());
 }
@@ -291,19 +291,19 @@
   std::string base_url = "http://foo/";
   std::string full_url = base_url + "hello?parameter=bar";
   network::URLLoaderCompletionStatus ok_status(net::OK);
-  ResourceResponseHead response_head = CreateResourceResponseHead(net::HTTP_OK);
+  mojom::URLResponseHeadPtr response_head = CreateURLResponseHead(net::HTTP_OK);
 
   StartRequest(full_url);
 
   // Default is non URL prefix match.
   EXPECT_FALSE(factory()->SimulateResponseForPendingRequest(
-      GURL(base_url), ok_status, response_head, /*content=*/""));
+      GURL(base_url), ok_status, response_head.Clone(), /*content=*/""));
   EXPECT_FALSE(factory()->SimulateResponseForPendingRequest(
-      GURL(base_url), ok_status, response_head, /*content=*/"",
+      GURL(base_url), ok_status, response_head.Clone(), /*content=*/"",
       TestURLLoaderFactory::kMatchDefault));
 
   EXPECT_TRUE(factory()->SimulateResponseForPendingRequest(
-      GURL(base_url), ok_status, response_head, /*content=*/"",
+      GURL(base_url), ok_status, response_head.Clone(), /*content=*/"",
       TestURLLoaderFactory::kUrlMatchPrefix));
 }
 
@@ -311,10 +311,10 @@
   std::string url = "http://foo/";
 
   network::URLLoaderCompletionStatus ok_status(net::OK);
-  ResourceResponseHead response_head = CreateResourceResponseHead(net::HTTP_OK);
+  mojom::URLResponseHeadPtr response_head = CreateURLResponseHead(net::HTTP_OK);
 
   EXPECT_FALSE(factory()->SimulateResponseForPendingRequest(
-      GURL(url), ok_status, response_head, /*content=*/"",
+      GURL(url), ok_status, response_head.Clone(), /*content=*/"",
       TestURLLoaderFactory::kMostRecentMatch));
 
   TestURLLoaderClient client1;
@@ -324,18 +324,18 @@
 
   // test non matching URL when there are pending requests.
   EXPECT_FALSE(factory()->SimulateResponseForPendingRequest(
-      GURL("http://bar"), ok_status, response_head, /*content=*/"",
+      GURL("http://bar"), ok_status, response_head.Clone(), /*content=*/"",
       TestURLLoaderFactory::kMostRecentMatch));
 
   EXPECT_EQ(2, factory()->NumPending());
   EXPECT_TRUE(factory()->SimulateResponseForPendingRequest(
-      GURL(url), ok_status, response_head, /*content=*/"",
+      GURL(url), ok_status, response_head.Clone(), /*content=*/"",
       TestURLLoaderFactory::kMostRecentMatch));
   EXPECT_EQ(1, factory()->NumPending());
   // Last sent request should have been served.
   EXPECT_TRUE(client2.has_received_completion());
   EXPECT_TRUE(factory()->SimulateResponseForPendingRequest(
-      GURL(url), ok_status, response_head, /*content=*/"",
+      GURL(url), ok_status, response_head.Clone(), /*content=*/"",
       TestURLLoaderFactory::kMostRecentMatch));
   EXPECT_EQ(0, factory()->NumPending());
   EXPECT_TRUE(client1.has_received_completion());
@@ -346,11 +346,11 @@
   // Raw-headers are not reported by default.
   StartRequest(url);
   network::URLLoaderCompletionStatus ok_status(net::OK);
-  ResourceResponseHead response_head = CreateResourceResponseHead(net::HTTP_OK);
+  mojom::URLResponseHeadPtr response_head = CreateURLResponseHead(net::HTTP_OK);
   EXPECT_TRUE(factory()->SimulateResponseForPendingRequest(
-      GURL(url), ok_status, response_head, /*content=*/""));
+      GURL(url), ok_status, std::move(response_head), /*content=*/""));
   EXPECT_TRUE(client()->has_received_completion());
-  EXPECT_FALSE(client()->response_head().raw_request_response_info);
+  EXPECT_FALSE(client()->response_head()->raw_request_response_info);
 }
 
 TEST_F(TestURLLoaderFactoryTest, SimulateResponseReportRawHeaders) {
@@ -360,23 +360,21 @@
   TestURLLoaderClient client;
   StartRequest(url, &client, /*load_flags=*/0, /*report_raw_headers=*/true);
   network::URLLoaderCompletionStatus ok_status(net::OK);
-  ResourceResponseHead response_head = CreateResourceResponseHead(
-      net::HTTP_NOT_FOUND, /*report_raw_headers=*/true);
-  AddCookiesToResourceResponseHead({cookie_line}, &response_head);
+  mojom::URLResponseHeadPtr response_head =
+      CreateURLResponseHead(net::HTTP_NOT_FOUND, /*report_raw_headers=*/true);
+  AddCookiesToURLResponseHead({cookie_line}, response_head.get());
   EXPECT_TRUE(factory()->SimulateResponseForPendingRequest(
-      GURL(url), ok_status, response_head, /*content=*/"hello"));
+      GURL(url), ok_status, std::move(response_head), /*content=*/"hello"));
   EXPECT_TRUE(client.has_received_completion());
-  scoped_refptr<HttpRawRequestResponseInfo> raw_response_info =
-      client.response_head().raw_request_response_info;
+  auto& raw_response_info = client.response_head()->raw_request_response_info;
   ASSERT_TRUE(raw_response_info);
   EXPECT_EQ(net::HTTP_NOT_FOUND, raw_response_info->http_status_code);
-  network::HttpRawRequestResponseInfo::HeadersVector headers =
-      raw_response_info->response_headers;
+  auto& headers = raw_response_info->response_headers;
   int cookie_count = 0;
   for (auto iter = headers.begin(); iter != headers.end(); ++iter) {
-    if (iter->first == "Set-Cookie") {
+    if ((*iter)->key == "Set-Cookie") {
       cookie_count++;
-      EXPECT_EQ(cookie_line, iter->second);
+      EXPECT_EQ(cookie_line, (*iter)->value);
     }
   }
 }
@@ -409,27 +407,27 @@
   // #2
   auto* request = &(*factory()->pending_requests())[1];
   factory()->SimulateResponseWithoutRemovingFromPendingList(
-      request, CreateResourceResponseHead(net::HTTP_NOT_FOUND), /*content=*/"",
+      request, CreateURLResponseHead(net::HTTP_NOT_FOUND), /*content=*/"",
       ok_status);
   // The pending request list remains untounched and successful.
   EXPECT_EQ(3, factory()->NumPending());
   EXPECT_TRUE(client_2.has_received_completion());
   EXPECT_EQ(net::OK, client_2.completion_status().error_code);
-  ASSERT_TRUE(client_2.response_head().headers);
+  ASSERT_TRUE(client_2.response_head()->headers);
   EXPECT_EQ(net::HTTP_NOT_FOUND,
-            client_2.response_head().headers->response_code());
+            client_2.response_head()->headers->response_code());
 
   // #1
   request = &(*factory()->pending_requests())[0];
   factory()->SimulateResponseWithoutRemovingFromPendingList(
-      request, CreateResourceResponseHead(net::HTTP_OK), /*content=*/"hello",
+      request, CreateURLResponseHead(net::HTTP_OK), /*content=*/"hello",
       ok_status);
   // Again, the pending request list remains untounched and successful.
   EXPECT_EQ(3, factory()->NumPending());
   EXPECT_TRUE(client_1.has_received_completion());
   EXPECT_EQ(net::OK, client_1.completion_status().error_code);
-  ASSERT_TRUE(client_1.response_head().headers);
-  EXPECT_EQ(net::HTTP_OK, client_1.response_head().headers->response_code());
+  ASSERT_TRUE(client_1.response_head()->headers);
+  EXPECT_EQ(net::HTTP_OK, client_1.response_head()->headers->response_code());
 
   // Ensure that when the client is unbound, it is counted out
   // of the pending request list.
@@ -448,14 +446,14 @@
   // # Process 4.
   request = &(*factory()->pending_requests())[3];
   factory()->SimulateResponseWithoutRemovingFromPendingList(
-      request, CreateResourceResponseHead(net::HTTP_OK), /*content=*/"hello",
+      request, CreateURLResponseHead(net::HTTP_OK), /*content=*/"hello",
       ok_status);
   // Again, the pending request list remains untounched and successful.
   EXPECT_EQ(3, factory()->NumPending());
   EXPECT_TRUE(client_4.has_received_completion());
   EXPECT_EQ(net::OK, client_4.completion_status().error_code);
-  ASSERT_TRUE(client_4.response_head().headers);
-  EXPECT_EQ(net::HTTP_OK, client_4.response_head().headers->response_code());
+  ASSERT_TRUE(client_4.response_head()->headers);
+  EXPECT_EQ(net::HTTP_OK, client_4.response_head()->headers->response_code());
 }
 
 }  // namespace network
diff --git a/services/network/test/test_utils.cc b/services/network/test/test_utils.cc
index 671e13c..a25eef121 100644
--- a/services/network/test/test_utils.cc
+++ b/services/network/test/test_utils.cc
@@ -6,8 +6,9 @@
 
 #include "base/strings/stringprintf.h"
 #include "net/http/http_util.h"
+#include "services/network/public/cpp/http_raw_request_response_info.h"
 #include "services/network/public/cpp/resource_request.h"
-#include "services/network/public/cpp/resource_response.h"
+#include "services/network/public/mojom/url_response_head.mojom.h"
 
 namespace network {
 
@@ -22,31 +23,30 @@
   return std::string(element.bytes(), element.length());
 }
 
-ResourceResponseHead CreateResourceResponseHead(net::HttpStatusCode http_status,
+mojom::URLResponseHeadPtr CreateURLResponseHead(net::HttpStatusCode http_status,
                                                 bool report_raw_headers) {
-  ResourceResponseHead head;
+  auto head = mojom::URLResponseHead::New();
   std::string status_line(
       base::StringPrintf("HTTP/1.1 %d %s", static_cast<int>(http_status),
                          net::GetHttpReasonPhrase(http_status)));
   std::string headers = status_line + "\nContent-type: text/html\n\n";
-  head.headers = base::MakeRefCounted<net::HttpResponseHeaders>(
+  head->headers = base::MakeRefCounted<net::HttpResponseHeaders>(
       net::HttpUtil::AssembleRawHeaders(headers));
   if (report_raw_headers) {
-    head.raw_request_response_info =
-        base::MakeRefCounted<HttpRawRequestResponseInfo>();
-    head.raw_request_response_info->http_status_text = status_line;
-    head.raw_request_response_info->http_status_code = http_status;
+    head->raw_request_response_info = mojom::HttpRawRequestResponseInfo::New();
+    head->raw_request_response_info->http_status_text = status_line;
+    head->raw_request_response_info->http_status_code = http_status;
   }
   return head;
 }
 
-void AddCookiesToResourceResponseHead(const std::vector<std::string>& cookies,
-                                      ResourceResponseHead* response_head) {
+void AddCookiesToURLResponseHead(const std::vector<std::string>& cookies,
+                                 mojom::URLResponseHead* response_head) {
   for (const auto& cookie_string : cookies) {
     response_head->headers->AddCookie(cookie_string);
     if (response_head->raw_request_response_info) {
       response_head->raw_request_response_info->response_headers.push_back(
-          std::make_pair("Set-Cookie", cookie_string));
+          mojom::HttpRawHeaderPair::New("Set-Cookie", cookie_string));
     }
   }
 }
diff --git a/services/network/test/test_utils.h b/services/network/test/test_utils.h
index 966936f..ce4ba45 100644
--- a/services/network/test/test_utils.h
+++ b/services/network/test/test_utils.h
@@ -9,27 +9,27 @@
 #include <vector>
 
 #include "net/http/http_status_code.h"
+#include "services/network/public/mojom/url_response_head.mojom-forward.h"
 
 namespace network {
 struct ResourceRequest;
-struct ResourceResponseHead;
 
 // Helper method to read the upload bytes from a ResourceRequest with a body.
 std::string GetUploadData(const network::ResourceRequest& request);
 
-// Helper methods used to create a ResourceResponseHead with the given status.
+// Helper methods used to create a mojom::URLResponseHead with the given status.
 // If |report_raw_headers| is true, the |raw_request_response_info| field of the
-// returned ResourceResponseHead is also set to contain the raw headers as
+// returned mojom::URLResponseHead is also set to contain the raw headers as
 // reported by the network stack (it's useful to report cookies, for example,
 // as they are filtered out of the net::HttpResponseHeaders when serialized).
-ResourceResponseHead CreateResourceResponseHead(
+mojom::URLResponseHeadPtr CreateURLResponseHead(
     net::HttpStatusCode http_status,
     bool report_raw_headers = false);
 
-// Adds cookies to the passed in ResourceResponseHead. If it was created with
+// Adds cookies to the passed in mojom::URLResponseHead. If it was created with
 // |report_raw_headers| true, the cookies are also added to the raw headers.
-void AddCookiesToResourceResponseHead(const std::vector<std::string>& cookies,
-                                      ResourceResponseHead* response_header);
+void AddCookiesToURLResponseHead(const std::vector<std::string>& cookies,
+                                 mojom::URLResponseHead* response_header);
 
 }  // namespace network
 
diff --git a/services/network/url_loader_unittest.cc b/services/network/url_loader_unittest.cc
index 46ff15b..d22957b 100644
--- a/services/network/url_loader_unittest.cc
+++ b/services/network/url_loader_unittest.cc
@@ -642,12 +642,12 @@
   // Convenience methods after calling Load();
   std::string mime_type() const {
     DCHECK(ran_);
-    return client_.response_head().mime_type;
+    return client_.response_head()->mime_type;
   }
 
   bool did_mime_sniff() const {
     DCHECK(ran_);
-    return client_.response_head().did_mime_sniff;
+    return client_.response_head()->did_mime_sniff;
   }
 
   const base::Optional<net::SSLInfo>& ssl_info() const {
@@ -805,15 +805,16 @@
 TEST_F(URLLoaderTest, AuthChallengeInfo) {
   GURL url = test_server()->GetURL("/auth-basic");
   EXPECT_EQ(net::OK, Load(url));
-  ASSERT_TRUE(client()->response_head().auth_challenge_info.has_value());
-  EXPECT_FALSE(client()->response_head().auth_challenge_info->is_proxy);
+  ASSERT_TRUE(client()->response_head()->auth_challenge_info.has_value());
+  EXPECT_FALSE(client()->response_head()->auth_challenge_info->is_proxy);
   EXPECT_EQ(url::Origin::Create(url),
-            client()->response_head().auth_challenge_info->challenger);
-  EXPECT_EQ("basic", client()->response_head().auth_challenge_info->scheme);
-  EXPECT_EQ("testrealm", client()->response_head().auth_challenge_info->realm);
+            client()->response_head()->auth_challenge_info->challenger);
+  EXPECT_EQ("basic", client()->response_head()->auth_challenge_info->scheme);
+  EXPECT_EQ("testrealm", client()->response_head()->auth_challenge_info->realm);
   EXPECT_EQ("Basic realm=\"testrealm\"",
-            client()->response_head().auth_challenge_info->challenge);
-  EXPECT_EQ("/auth-basic", client()->response_head().auth_challenge_info->path);
+            client()->response_head()->auth_challenge_info->challenge);
+  EXPECT_EQ("/auth-basic",
+            client()->response_head()->auth_challenge_info->path);
 }
 
 // Tests that no auth challenge info is present on the response when a request
@@ -821,7 +822,7 @@
 TEST_F(URLLoaderTest, NoAuthChallengeInfo) {
   GURL url = test_server()->GetURL("/");
   EXPECT_EQ(net::OK, Load(url));
-  EXPECT_FALSE(client()->response_head().auth_challenge_info.has_value());
+  EXPECT_FALSE(client()->response_head()->auth_challenge_info.has_value());
 }
 
 // Test decoded_body_length / encoded_body_length when they're different.
@@ -2310,7 +2311,7 @@
 
   EXPECT_EQ(net::OK, Load(GURL("https://example.test/")));
   EXPECT_EQ(net::CERT_STATUS_DATE_INVALID,
-            client()->response_head().cert_status);
+            client()->response_head()->cert_status);
 }
 
 // Verifies if URLLoader works well with ResourceScheduler.
@@ -2811,12 +2812,12 @@
   client()->RunUntilComplete();
   EXPECT_TRUE(client()->has_received_completion());
   scoped_refptr<net::HttpResponseHeaders> headers =
-      client()->response_head().headers;
+      client()->response_head()->headers;
   ASSERT_TRUE(headers);
   EXPECT_EQ(200, headers->response_code());
   EXPECT_EQ(1, network_context_client.on_auth_required_call_counter());
   ASSERT_FALSE(url_loader);
-  EXPECT_FALSE(client()->response_head().auth_challenge_info.has_value());
+  EXPECT_FALSE(client()->response_head()->auth_challenge_info.has_value());
 }
 
 TEST_F(URLLoaderTest, CancelAuth) {
@@ -2855,7 +2856,7 @@
   client()->RunUntilComplete();
   EXPECT_TRUE(client()->has_received_completion());
   scoped_refptr<net::HttpResponseHeaders> headers =
-      client()->response_head().headers;
+      client()->response_head()->headers;
   ASSERT_TRUE(headers);
   EXPECT_EQ(401, headers->response_code());
   EXPECT_EQ(1, network_context_client.on_auth_required_call_counter());
@@ -2899,7 +2900,7 @@
   client()->RunUntilComplete();
   EXPECT_TRUE(client()->has_received_completion());
   scoped_refptr<net::HttpResponseHeaders> headers =
-      client()->response_head().headers;
+      client()->response_head()->headers;
   ASSERT_TRUE(headers);
   EXPECT_EQ(200, headers->response_code());
   EXPECT_EQ(2, network_context_client.on_auth_required_call_counter());
@@ -2944,7 +2945,7 @@
   client()->RunUntilComplete();
   EXPECT_TRUE(client()->has_received_completion());
   scoped_refptr<net::HttpResponseHeaders> headers =
-      client()->response_head().headers;
+      client()->response_head()->headers;
   ASSERT_TRUE(headers);
   EXPECT_EQ(200, headers->response_code());
   // No auth required for favicon.
@@ -4389,11 +4390,11 @@
 
     EXPECT_EQ("policy=policy-1", mock_origin_policy_manager.header_value());
     EXPECT_TRUE(mock_origin_policy_manager.retrieve_origin_policy_called());
-    EXPECT_TRUE(loader_client.response_head().origin_policy.has_value());
+    EXPECT_TRUE(loader_client.response_head()->origin_policy.has_value());
     EXPECT_EQ(OriginPolicyState::kLoaded,
-              loader_client.response_head().origin_policy.value().state);
+              loader_client.response_head()->origin_policy.value().state);
     EXPECT_EQ(server.base_url(),
-              loader_client.response_head().origin_policy.value().policy_url);
+              loader_client.response_head()->origin_policy.value().policy_url);
   }
 
   // If the "Sec-Origin-Policy" header is not present in the response, still
@@ -4426,11 +4427,11 @@
 
     EXPECT_EQ("", mock_origin_policy_manager.header_value());
     EXPECT_TRUE(mock_origin_policy_manager.retrieve_origin_policy_called());
-    EXPECT_TRUE(loader_client.response_head().origin_policy.has_value());
+    EXPECT_TRUE(loader_client.response_head()->origin_policy.has_value());
     EXPECT_EQ(OriginPolicyState::kLoaded,
-              loader_client.response_head().origin_policy.value().state);
+              loader_client.response_head()->origin_policy.value().state);
     EXPECT_EQ(server.base_url(),
-              loader_client.response_head().origin_policy.value().policy_url);
+              loader_client.response_head()->origin_policy.value().policy_url);
   }
 
   // If "obey_origin_policy" is not set, don't call the origin policy manager
@@ -4462,7 +4463,7 @@
     delete_run_loop.Run();
 
     EXPECT_FALSE(mock_origin_policy_manager.retrieve_origin_policy_called());
-    EXPECT_FALSE(loader_client.response_head().origin_policy.has_value());
+    EXPECT_FALSE(loader_client.response_head()->origin_policy.has_value());
   }
 }
 
diff --git a/services/viz/public/cpp/compositing/quads_mojom_traits.cc b/services/viz/public/cpp/compositing/quads_mojom_traits.cc
index e41f086..aef20cbf 100644
--- a/services/viz/public/cpp/compositing/quads_mojom_traits.cc
+++ b/services/viz/public/cpp/compositing/quads_mojom_traits.cc
@@ -109,8 +109,7 @@
              &quad->overlay_resources.size_in_pixels
                   [viz::StreamVideoDrawQuad::kResourceIdIndex]) &&
          data.ReadUvTopLeft(&quad->uv_top_left) &&
-         data.ReadUvBottomRight(&quad->uv_bottom_right) &&
-         data.ReadYcbcrInfo(&quad->ycbcr_info);
+         data.ReadUvBottomRight(&quad->uv_bottom_right);
 }
 
 // static
diff --git a/services/viz/public/cpp/compositing/quads_mojom_traits.h b/services/viz/public/cpp/compositing/quads_mojom_traits.h
index b1cc3237..7174c8c 100644
--- a/services/viz/public/cpp/compositing/quads_mojom_traits.h
+++ b/services/viz/public/cpp/compositing/quads_mojom_traits.h
@@ -18,8 +18,6 @@
 #include "components/viz/common/quads/tile_draw_quad.h"
 #include "components/viz/common/quads/video_hole_draw_quad.h"
 #include "components/viz/common/quads/yuv_video_draw_quad.h"
-#include "gpu/ipc/common/vulkan_ycbcr_info.h"
-#include "gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h"
 #include "services/viz/public/cpp/compositing/filter_operation_mojom_traits.h"
 #include "services/viz/public/cpp/compositing/filter_operations_mojom_traits.h"
 #include "services/viz/public/cpp/compositing/shared_quad_state_mojom_traits.h"
@@ -303,13 +301,6 @@
     return quad->uv_bottom_right;
   }
 
-  static const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info(
-      const viz::DrawQuad& input) {
-    const viz::StreamVideoDrawQuad* quad =
-        viz::StreamVideoDrawQuad::MaterialCast(&input);
-    return quad->ycbcr_info;
-  }
-
   static bool Read(viz::mojom::StreamVideoQuadStateDataView data,
                    viz::DrawQuad* out);
 };
diff --git a/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.cc b/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.cc
index 39a3ba8..a6468df 100644
--- a/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.cc
+++ b/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.cc
@@ -19,8 +19,10 @@
          viz::TransferableResource* out) {
   if (!data.ReadSize(&out->size) ||
       !data.ReadMailboxHolder(&out->mailbox_holder) ||
-      !data.ReadColorSpace(&out->color_space))
+      !data.ReadColorSpace(&out->color_space) ||
+      !data.ReadYcbcrInfo(&out->ycbcr_info)) {
     return false;
+  }
   out->id = data.id();
   out->format = static_cast<viz::ResourceFormat>(data.format());
   out->filter = data.filter();
diff --git a/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.h b/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.h
index df58fa1..e6a97174 100644
--- a/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.h
+++ b/services/viz/public/cpp/compositing/transferable_resource_mojom_traits.h
@@ -7,6 +7,8 @@
 
 #include "build/build_config.h"
 #include "components/viz/common/resources/transferable_resource.h"
+#include "gpu/ipc/common/vulkan_ycbcr_info.h"
+#include "gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h"
 #include "services/viz/public/mojom/compositing/transferable_resource.mojom-shared.h"
 #include "ui/gfx/ipc/color/gfx_param_traits.h"
 
@@ -76,6 +78,11 @@
     return resource.color_space;
   }
 
+  static const base::Optional<gpu::VulkanYCbCrInfo>& ycbcr_info(
+      const viz::TransferableResource& resource) {
+    return resource.ycbcr_info;
+  }
+
   static bool Read(viz::mojom::TransferableResourceDataView data,
                    viz::TransferableResource* out);
 };
diff --git a/services/viz/public/mojom/compositing/quads.mojom b/services/viz/public/mojom/compositing/quads.mojom
index 438c869..3755f70 100644
--- a/services/viz/public/mojom/compositing/quads.mojom
+++ b/services/viz/public/mojom/compositing/quads.mojom
@@ -4,10 +4,9 @@
 
 module viz.mojom;
 
-import "gpu/ipc/common/vulkan_ycbcr_info.mojom";
 import "mojo/public/mojom/base/unguessable_token.mojom";
-import "services/viz/public/mojom/compositing/surface_range.mojom";
 import "services/viz/public/mojom/compositing/shared_quad_state.mojom";
+import "services/viz/public/mojom/compositing/surface_range.mojom";
 import "ui/gfx/geometry/mojom/geometry.mojom";
 import "ui/gfx/mojom/color_space.mojom";
 import "ui/gfx/mojom/transform.mojom";
@@ -62,7 +61,6 @@
   gfx.mojom.Size resource_size_in_pixels;
   gfx.mojom.PointF uv_top_left;
   gfx.mojom.PointF uv_bottom_right;
-  gpu.mojom.VulkanYCbCrInfo? ycbcr_info;
 };
 
 struct SurfaceQuadState {
diff --git a/services/viz/public/mojom/compositing/transferable_resource.mojom b/services/viz/public/mojom/compositing/transferable_resource.mojom
index 8a9feadb..5207ce5 100644
--- a/services/viz/public/mojom/compositing/transferable_resource.mojom
+++ b/services/viz/public/mojom/compositing/transferable_resource.mojom
@@ -5,9 +5,10 @@
 module viz.mojom;
 
 import "gpu/ipc/common/mailbox_holder.mojom";
+import "gpu/ipc/common/vulkan_ycbcr_info.mojom";
 import "ui/gfx/geometry/mojom/geometry.mojom";
-import "ui/gfx/mojom/color_space.mojom";
 import "ui/gfx/mojom/buffer_types.mojom";
+import "ui/gfx/mojom/color_space.mojom";
 
 // Corresponds to viz::ResourceFormat.
 enum ResourceFormat {
@@ -47,4 +48,5 @@
   bool is_backed_by_surface_texture;
   bool wants_promotion_hint;
   gfx.mojom.ColorSpace color_space;
+  gpu.mojom.VulkanYCbCrInfo ? ycbcr_info;
 };
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index 94e9588a..ea8db69 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -205,6 +205,10 @@
 #define SK_USE_LEGACY_DISTANCE_FIELDS
 #endif
 
+#ifndef SK_SUPPORT_LEGACY_COLORFILTER_NO_SHADER
+#define SK_SUPPORT_LEGACY_COLORFILTER_NO_SHADER
+#endif
+
 // For now, Chrome should only attempt to reduce opList splitting when recording
 // DDLs
 #ifndef SK_DISABLE_REDUCE_OPLIST_SPLITTING
diff --git a/storage/browser/blob/blob_storage_context.cc b/storage/browser/blob/blob_storage_context.cc
index 18c9f9c6..a2bb4c0 100644
--- a/storage/browser/blob/blob_storage_context.cc
+++ b/storage/browser/blob/blob_storage_context.cc
@@ -29,6 +29,7 @@
 #include "storage/browser/blob/blob_data_builder.h"
 #include "storage/browser/blob/blob_data_item.h"
 #include "storage/browser/blob/blob_data_snapshot.h"
+#include "storage/browser/blob/blob_impl.h"
 #include "storage/browser/blob/shareable_blob_data_item.h"
 #include "third_party/blink/public/common/blob/blob_utils.h"
 #include "url/gurl.h"
@@ -66,13 +67,9 @@
   return CreateHandle(uuid, entry);
 }
 
-std::unique_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromPublicURL(
-    const GURL& url) {
-  std::string uuid;
-  BlobEntry* entry = registry_.GetEntryFromURL(url, &uuid);
-  if (!entry)
-    return nullptr;
-  return CreateHandle(uuid, entry);
+mojo::PendingRemote<blink::mojom::Blob>
+BlobStorageContext::GetBlobFromPublicURL(const GURL& url) {
+  return registry_.GetBlobFromURL(url);
 }
 
 void BlobStorageContext::GetBlobDataFromBlobRemote(
@@ -142,19 +139,14 @@
   return CreateHandle(uuid, entry);
 }
 
-bool BlobStorageContext::RegisterPublicBlobURL(const GURL& blob_url,
-                                               const std::string& uuid) {
-  if (!registry_.CreateUrlMapping(blob_url, uuid))
-    return false;
-  IncrementBlobRefCount(uuid);
-  return true;
+bool BlobStorageContext::RegisterPublicBlobURL(
+    const GURL& blob_url,
+    mojo::PendingRemote<blink::mojom::Blob> blob) {
+  return registry_.CreateUrlMapping(blob_url, std::move(blob));
 }
 
 void BlobStorageContext::RevokePublicBlobURL(const GURL& blob_url) {
-  std::string uuid;
-  if (!registry_.DeleteURLMapping(blob_url, &uuid))
-    return;
-  DecrementBlobRefCount(uuid);
+  registry_.DeleteURLMapping(blob_url);
 }
 
 std::unique_ptr<BlobDataHandle> BlobStorageContext::AddFutureBlob(
diff --git a/storage/browser/blob/blob_storage_context.h b/storage/browser/blob/blob_storage_context.h
index 6f53380..c4fdee53 100644
--- a/storage/browser/blob/blob_storage_context.h
+++ b/storage/browser/blob/blob_storage_context.h
@@ -61,7 +61,7 @@
   // The following three methods all lookup a BlobDataHandle based on some
   // input. If no blob matching the input exists these methods return null.
   std::unique_ptr<BlobDataHandle> GetBlobDataFromUUID(const std::string& uuid);
-  std::unique_ptr<BlobDataHandle> GetBlobDataFromPublicURL(const GURL& url);
+  mojo::PendingRemote<blink::mojom::Blob> GetBlobFromPublicURL(const GURL& url);
   // If this BlobStorageContext is deleted before this method finishes, the
   // callback will still be called with null.
   void GetBlobDataFromBlobRemote(
@@ -87,7 +87,8 @@
       BlobStatus reason);
 
   // Useful for coining blob urls from within the browser process.
-  bool RegisterPublicBlobURL(const GURL& url, const std::string& uuid);
+  bool RegisterPublicBlobURL(const GURL& url,
+                             mojo::PendingRemote<blink::mojom::Blob> blob);
   void RevokePublicBlobURL(const GURL& url);
 
   size_t blob_count() const { return registry_.blob_count(); }
diff --git a/storage/browser/blob/blob_storage_context_unittest.cc b/storage/browser/blob/blob_storage_context_unittest.cc
index eaa8927..2188c6e 100644
--- a/storage/browser/blob/blob_storage_context_unittest.cc
+++ b/storage/browser/blob/blob_storage_context_unittest.cc
@@ -28,6 +28,7 @@
 #include "storage/browser/blob/blob_data_handle.h"
 #include "storage/browser/blob/blob_data_item.h"
 #include "storage/browser/blob/blob_data_snapshot.h"
+#include "storage/browser/blob/blob_impl.h"
 #include "storage/browser/test/fake_blob_data_handle.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -111,6 +112,20 @@
     context_->DecrementBlobRefCount(uuid);
   }
 
+  std::string UUIDFromBlob(blink::mojom::Blob* blob) {
+    base::RunLoop loop;
+    std::string received_uuid;
+    blob->GetInternalUUID(base::BindOnce(
+        [](base::OnceClosure quit_closure, std::string* uuid_out,
+           const std::string& uuid) {
+          *uuid_out = uuid;
+          std::move(quit_closure).Run();
+        },
+        loop.QuitClosure(), &received_uuid));
+    loop.Run();
+    return received_uuid;
+  }
+
   std::vector<FileCreationInfo> files_;
   base::ScopedTempDir temp_dir_;
   scoped_refptr<TestSimpleTaskRunner> file_runner_ = new TestSimpleTaskRunner();
@@ -606,31 +621,33 @@
 TEST_F(BlobStorageContextTest, PublicBlobUrls) {
   // Build up a basic blob.
   const std::string kId("id");
-  std::unique_ptr<BlobDataHandle> first_handle = SetupBasicBlob(kId);
+  mojo::PendingRemote<blink::mojom::Blob> pending_blob_remote;
+  BlobImpl::Create(SetupBasicBlob(kId),
+                   pending_blob_remote.InitWithNewPipeAndPassReceiver());
 
   // Now register a url for that blob.
   GURL kUrl("blob:id");
-  context_->RegisterPublicBlobURL(kUrl, kId);
-  std::unique_ptr<BlobDataHandle> blob_data_handle =
-      context_->GetBlobDataFromPublicURL(kUrl);
-  ASSERT_TRUE(blob_data_handle.get());
-  EXPECT_EQ(kId, blob_data_handle->uuid());
-  std::unique_ptr<BlobDataSnapshot> data = blob_data_handle->CreateSnapshot();
-  blob_data_handle.reset();
-  first_handle.reset();
+  context_->RegisterPublicBlobURL(kUrl, std::move(pending_blob_remote));
+  pending_blob_remote = context_->GetBlobFromPublicURL(kUrl);
+  ASSERT_TRUE(pending_blob_remote);
+  mojo::Remote<blink::mojom::Blob> blob_remote(std::move(pending_blob_remote));
+  EXPECT_EQ(kId, UUIDFromBlob(blob_remote.get()));
+  blob_remote.reset();
   base::RunLoop().RunUntilIdle();
 
   // The url registration should keep the blob alive even after
   // explicit references are dropped.
-  blob_data_handle = context_->GetBlobDataFromPublicURL(kUrl);
-  EXPECT_TRUE(blob_data_handle);
-  blob_data_handle.reset();
+  pending_blob_remote = context_->GetBlobFromPublicURL(kUrl);
+  EXPECT_TRUE(pending_blob_remote);
+  pending_blob_remote.reset();
 
   base::RunLoop().RunUntilIdle();
   // Finally get rid of the url registration and the blob.
   context_->RevokePublicBlobURL(kUrl);
-  blob_data_handle = context_->GetBlobDataFromPublicURL(kUrl);
-  EXPECT_FALSE(blob_data_handle.get());
+  pending_blob_remote = context_->GetBlobFromPublicURL(kUrl);
+  EXPECT_FALSE(pending_blob_remote);
+  base::RunLoop().RunUntilIdle();
+
   EXPECT_FALSE(context_->registry().HasEntry(kId));
 }
 
diff --git a/storage/browser/blob/blob_storage_registry.cc b/storage/browser/blob/blob_storage_registry.cc
index 0ad1ecc..b282a43 100644
--- a/storage/browser/blob/blob_storage_registry.cc
+++ b/storage/browser/blob/blob_storage_registry.cc
@@ -56,63 +56,64 @@
   return const_cast<BlobStorageRegistry*>(this)->GetEntry(uuid);
 }
 
-bool BlobStorageRegistry::CreateUrlMapping(const GURL& blob_url,
-                                           const std::string& uuid) {
+bool BlobStorageRegistry::CreateUrlMapping(
+    const GURL& blob_url,
+    mojo::PendingRemote<blink::mojom::Blob> blob) {
   DCHECK(!BlobUrlUtils::UrlHasFragment(blob_url));
-  if (blob_map_.find(uuid) == blob_map_.end() || IsURLMapped(blob_url))
+  if (IsURLMapped(blob_url))
     return false;
-  url_to_uuid_[blob_url] = uuid;
+  url_to_blob_[blob_url] = mojo::Remote<blink::mojom::Blob>(std::move(blob));
   return true;
 }
 
-bool BlobStorageRegistry::DeleteURLMapping(const GURL& blob_url,
-                                           std::string* uuid) {
+bool BlobStorageRegistry::DeleteURLMapping(const GURL& blob_url) {
   DCHECK(!BlobUrlUtils::UrlHasFragment(blob_url));
-  auto found = url_to_uuid_.find(blob_url);
-  if (found == url_to_uuid_.end())
+  auto found = url_to_blob_.find(blob_url);
+  if (found == url_to_blob_.end())
     return false;
-  if (uuid)
-    uuid->assign(found->second);
-  url_to_uuid_.erase(found);
+  url_to_blob_.erase(found);
   return true;
 }
 
 bool BlobStorageRegistry::IsURLMapped(const GURL& blob_url) const {
-  return url_to_uuid_.find(blob_url) != url_to_uuid_.end();
+  return url_to_blob_.find(blob_url) != url_to_blob_.end();
 }
 
-BlobEntry* BlobStorageRegistry::GetEntryFromURL(const GURL& url,
-                                                std::string* uuid) {
-  auto found = url_to_uuid_.find(BlobUrlUtils::ClearUrlFragment(url));
-  if (found == url_to_uuid_.end())
-    return nullptr;
-  BlobEntry* entry = GetEntry(found->second);
-  if (entry && uuid)
-    uuid->assign(found->second);
-  return entry;
+mojo::PendingRemote<blink::mojom::Blob> BlobStorageRegistry::GetBlobFromURL(
+    const GURL& url) {
+  auto found = url_to_blob_.find(BlobUrlUtils::ClearUrlFragment(url));
+  if (found == url_to_blob_.end())
+    return mojo::NullRemote();
+  mojo::PendingRemote<blink::mojom::Blob> result;
+  found->second->Clone(result.InitWithNewPipeAndPassReceiver());
+  return result;
 }
 
-void BlobStorageRegistry::AddTokenMapping(const base::UnguessableToken& token,
-                                          const GURL& url,
-                                          const std::string& uuid) {
-  DCHECK(token_to_url_and_uuid_.find(token) == token_to_url_and_uuid_.end());
-  token_to_url_and_uuid_.emplace(token, std::make_pair(url, uuid));
+void BlobStorageRegistry::AddTokenMapping(
+    const base::UnguessableToken& token,
+    const GURL& url,
+    mojo::PendingRemote<blink::mojom::Blob> blob) {
+  DCHECK(token_to_url_and_blob_.find(token) == token_to_url_and_blob_.end());
+  token_to_url_and_blob_.emplace(
+      token,
+      std::make_pair(url, mojo::Remote<blink::mojom::Blob>(std::move(blob))));
 }
 
 void BlobStorageRegistry::RemoveTokenMapping(
     const base::UnguessableToken& token) {
-  DCHECK(token_to_url_and_uuid_.find(token) != token_to_url_and_uuid_.end());
-  token_to_url_and_uuid_.erase(token);
+  DCHECK(token_to_url_and_blob_.find(token) != token_to_url_and_blob_.end());
+  token_to_url_and_blob_.erase(token);
 }
 
-bool BlobStorageRegistry::GetTokenMapping(const base::UnguessableToken& token,
-                                          GURL* url,
-                                          std::string* uuid) const {
-  auto it = token_to_url_and_uuid_.find(token);
-  if (it == token_to_url_and_uuid_.end())
+bool BlobStorageRegistry::GetTokenMapping(
+    const base::UnguessableToken& token,
+    GURL* url,
+    mojo::PendingRemote<blink::mojom::Blob>* blob) const {
+  auto it = token_to_url_and_blob_.find(token);
+  if (it == token_to_url_and_blob_.end())
     return false;
   *url = it->second.first;
-  *uuid = it->second.second;
+  it->second.second->Clone(blob->InitWithNewPipeAndPassReceiver());
   return true;
 }
 
diff --git a/storage/browser/blob/blob_storage_registry.h b/storage/browser/blob/blob_storage_registry.h
index 7bb79e7..9127899 100644
--- a/storage/browser/blob/blob_storage_registry.h
+++ b/storage/browser/blob/blob_storage_registry.h
@@ -17,7 +17,10 @@
 #include "base/component_export.h"
 #include "base/macros.h"
 #include "base/unguessable_token.h"
+#include "mojo/public/cpp/bindings/pending_remote.h"
+#include "mojo/public/cpp/bindings/remote.h"
 #include "storage/browser/blob/blob_storage_constants.h"
+#include "third_party/blink/public/mojom/blob/blob.mojom.h"
 
 class GURL;
 
@@ -51,39 +54,40 @@
   BlobEntry* GetEntry(const std::string& uuid);
   const BlobEntry* GetEntry(const std::string& uuid) const;
 
-  // Creates a url mapping from blob uuid to the given url. Returns false if
-  // the uuid isn't mapped to an entry or if there already is a map for the URL.
-  bool CreateUrlMapping(const GURL& url, const std::string& uuid);
+  // Creates a url mapping from blob to the given url. Returns false if
+  // there already is a map for the URL.
+  bool CreateUrlMapping(const GURL& url,
+                        mojo::PendingRemote<blink::mojom::Blob> blob);
 
-  // Removes the given URL mapping. Optionally populates a uuid string of the
-  // removed entry uuid. Returns false if the url isn't mapped.
-  bool DeleteURLMapping(const GURL& url, std::string* uuid);
+  // Removes the given URL mapping. Returns false if the url wasn't mapped.
+  bool DeleteURLMapping(const GURL& url);
 
-  // Returns if the url is mapped to a blob uuid.
+  // Returns if the url is mapped to a blob.
   bool IsURLMapped(const GURL& blob_url) const;
 
-  // Returns the entry from the given url, and optionally populates the uuid for
-  // that entry. Returns a nullptr if the mapping or entry doesn't exist.
-  BlobEntry* GetEntryFromURL(const GURL& url, std::string* uuid);
+  // Returns the blob from the given url. Returns a null remote if the mapping
+  // doesn't exist.
+  mojo::PendingRemote<blink::mojom::Blob> GetBlobFromURL(const GURL& url);
 
   size_t blob_count() const { return blob_map_.size(); }
-  size_t url_count() const { return url_to_uuid_.size(); }
+  size_t url_count() const { return url_to_blob_.size(); }
 
   void AddTokenMapping(const base::UnguessableToken& token,
                        const GURL& url,
-                       const std::string& uuid);
+                       mojo::PendingRemote<blink::mojom::Blob> blob);
   void RemoveTokenMapping(const base::UnguessableToken& token);
   bool GetTokenMapping(const base::UnguessableToken& token,
                        GURL* url,
-                       std::string* uuid) const;
+                       mojo::PendingRemote<blink::mojom::Blob>* blob) const;
 
  private:
   friend class ViewBlobInternalsJob;
 
   std::unordered_map<std::string, std::unique_ptr<BlobEntry>> blob_map_;
-  std::map<GURL, std::string> url_to_uuid_;
-  std::map<base::UnguessableToken, std::pair<GURL, std::string>>
-      token_to_url_and_uuid_;
+  std::map<GURL, mojo::Remote<blink::mojom::Blob>> url_to_blob_;
+  std::map<base::UnguessableToken,
+           std::pair<GURL, mojo::Remote<blink::mojom::Blob>>>
+      token_to_url_and_blob_;
 
   DISALLOW_COPY_AND_ASSIGN(BlobStorageRegistry);
 };
diff --git a/storage/browser/blob/blob_storage_registry_unittest.cc b/storage/browser/blob/blob_storage_registry_unittest.cc
index 9cb2285..d9c12c9 100644
--- a/storage/browser/blob/blob_storage_registry_unittest.cc
+++ b/storage/browser/blob/blob_storage_registry_unittest.cc
@@ -5,7 +5,10 @@
 #include "storage/browser/blob/blob_storage_registry.h"
 
 #include "base/callback.h"
+#include "base/run_loop.h"
+#include "base/test/task_environment.h"
 #include "storage/browser/blob/blob_entry.h"
+#include "storage/browser/test/fake_blob.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
 
@@ -35,46 +38,57 @@
   EXPECT_EQ(1u, registry.blob_count());
 }
 
+std::string UUIDFromBlob(mojo::PendingRemote<blink::mojom::Blob> pending_blob) {
+  mojo::Remote<blink::mojom::Blob> blob(std::move(pending_blob));
+
+  base::RunLoop loop;
+  std::string received_uuid;
+  blob->GetInternalUUID(base::BindOnce(
+      [](base::OnceClosure quit_closure, std::string* uuid_out,
+         const std::string& uuid) {
+        *uuid_out = uuid;
+        std::move(quit_closure).Run();
+      },
+      loop.QuitClosure(), &received_uuid));
+  loop.Run();
+  return received_uuid;
+}
+
 TEST(BlobStorageRegistry, URLRegistration) {
-  const std::string kBlob = "Blob1";
+  const std::string kBlobId1 = "Blob1";
   const std::string kType = "type1";
   const std::string kDisposition = "disp1";
-  const std::string kBlob2 = "Blob2";
+  const std::string kBlobId2 = "Blob2";
   const GURL kURL = GURL("blob://Blob1");
   const GURL kURL2 = GURL("blob://Blob2");
+
+  base::test::SingleThreadTaskEnvironment task_environment_;
+
+  FakeBlob blob1(kBlobId1);
+  FakeBlob blob2(kBlobId2);
+
   BlobStorageRegistry registry;
-
   EXPECT_FALSE(registry.IsURLMapped(kURL));
-  EXPECT_EQ(nullptr, registry.GetEntryFromURL(kURL, nullptr));
-  EXPECT_FALSE(registry.DeleteURLMapping(kURL, nullptr));
-  EXPECT_FALSE(registry.CreateUrlMapping(kURL, kBlob));
+  EXPECT_FALSE(registry.GetBlobFromURL(kURL));
+  EXPECT_FALSE(registry.DeleteURLMapping(kURL));
   EXPECT_EQ(0u, registry.url_count());
-  BlobEntry* entry = registry.CreateEntry(kBlob, kType, kDisposition);
 
-  EXPECT_FALSE(registry.IsURLMapped(kURL));
-  EXPECT_TRUE(registry.CreateUrlMapping(kURL, kBlob));
-  EXPECT_FALSE(registry.CreateUrlMapping(kURL, kBlob2));
+  EXPECT_TRUE(registry.CreateUrlMapping(kURL, blob1.Clone()));
+  EXPECT_FALSE(registry.CreateUrlMapping(kURL, blob2.Clone()));
 
   EXPECT_TRUE(registry.IsURLMapped(kURL));
-  EXPECT_EQ(entry, registry.GetEntryFromURL(kURL, nullptr));
-  std::string uuid;
-  EXPECT_EQ(entry, registry.GetEntryFromURL(kURL, &uuid));
-  EXPECT_EQ(kBlob, uuid);
+  EXPECT_EQ(kBlobId1, UUIDFromBlob(registry.GetBlobFromURL(kURL)));
   EXPECT_EQ(1u, registry.url_count());
 
-  registry.CreateEntry(kBlob2, kType, kDisposition);
-  EXPECT_TRUE(registry.CreateUrlMapping(kURL2, kBlob2));
+  EXPECT_TRUE(registry.CreateUrlMapping(kURL2, blob2.Clone()));
   EXPECT_EQ(2u, registry.url_count());
-  EXPECT_TRUE(registry.DeleteURLMapping(kURL2, &uuid));
-  EXPECT_EQ(kBlob2, uuid);
+  EXPECT_TRUE(registry.DeleteURLMapping(kURL2));
   EXPECT_FALSE(registry.IsURLMapped(kURL2));
 
   // Both urls point to the same blob.
-  EXPECT_TRUE(registry.CreateUrlMapping(kURL2, kBlob));
-  std::string uuid2;
-  EXPECT_EQ(registry.GetEntryFromURL(kURL, &uuid),
-            registry.GetEntryFromURL(kURL2, &uuid2));
-  EXPECT_EQ(uuid, uuid2);
+  EXPECT_TRUE(registry.CreateUrlMapping(kURL2, blob1.Clone()));
+  EXPECT_EQ(UUIDFromBlob(registry.GetBlobFromURL(kURL)),
+            UUIDFromBlob(registry.GetBlobFromURL(kURL2)));
 }
 
 }  // namespace
diff --git a/storage/browser/blob/blob_url_loader_factory.cc b/storage/browser/blob/blob_url_loader_factory.cc
index 5119a09..4c34edc3 100644
--- a/storage/browser/blob/blob_url_loader_factory.cc
+++ b/storage/browser/blob/blob_url_loader_factory.cc
@@ -22,24 +22,46 @@
                            const base::WeakPtr<BlobStorageContext>& context,
                            network::mojom::URLLoaderFactoryRequest request,
                            const base::UnguessableToken& token) {
-  std::unique_ptr<BlobDataHandle> handle;
+  mojo::PendingRemote<blink::mojom::Blob> blob;
   GURL blob_url;
-  if (context) {
-    std::string uuid;
-    if (context->registry().GetTokenMapping(token, &blob_url, &uuid))
-      handle = context->GetBlobDataFromUUID(uuid);
-  }
-  BlobURLLoaderFactory::Create(std::move(handle), blob_url, std::move(request));
+  if (context)
+    context->registry().GetTokenMapping(token, &blob_url, &blob);
+  BlobURLLoaderFactory::Create(std::move(blob), blob_url, context,
+                               std::move(request));
 }
 
 }  // namespace
 
 // static
 void BlobURLLoaderFactory::Create(
-    std::unique_ptr<BlobDataHandle> handle,
+    mojo::PendingRemote<blink::mojom::Blob> pending_blob,
     const GURL& blob_url,
+    base::WeakPtr<BlobStorageContext> context,
     network::mojom::URLLoaderFactoryRequest request) {
-  new BlobURLLoaderFactory(std::move(handle), blob_url, std::move(request));
+  if (!pending_blob) {
+    new BlobURLLoaderFactory(nullptr, blob_url, std::move(request));
+    return;
+  }
+  // Not every URLLoaderFactory user deals with the URLLoaderFactory simply
+  // disconnecting very well, so make sure we always at least bind the request
+  // to some factory that can then fail with a network error. Hence the callback
+  // is wrapped in WrapCallbackWithDefaultInvokeIfNotRun.
+  mojo::Remote<blink::mojom::Blob> blob(std::move(pending_blob));
+  blink::mojom::Blob* raw_blob = blob.get();
+  raw_blob->GetInternalUUID(mojo::WrapCallbackWithDefaultInvokeIfNotRun(
+      base::BindOnce(
+          [](mojo::Remote<blink::mojom::Blob>,
+             base::WeakPtr<BlobStorageContext> context, const GURL& blob_url,
+             network::mojom::URLLoaderFactoryRequest request,
+             const std::string& uuid) {
+            std::unique_ptr<BlobDataHandle> blob;
+            if (context)
+              blob = context->GetBlobDataFromUUID(uuid);
+            new BlobURLLoaderFactory(std::move(blob), blob_url,
+                                     std::move(request));
+          },
+          std::move(blob), std::move(context), blob_url, std::move(request)),
+      ""));
 }
 
 // static
diff --git a/storage/browser/blob/blob_url_loader_factory.h b/storage/browser/blob/blob_url_loader_factory.h
index 9f796ca..e8600ba 100644
--- a/storage/browser/blob/blob_url_loader_factory.h
+++ b/storage/browser/blob/blob_url_loader_factory.h
@@ -21,8 +21,9 @@
 class COMPONENT_EXPORT(STORAGE_BROWSER) BlobURLLoaderFactory
     : public network::mojom::URLLoaderFactory {
  public:
-  static void Create(std::unique_ptr<BlobDataHandle> handle,
+  static void Create(mojo::PendingRemote<blink::mojom::Blob> blob,
                      const GURL& blob_url,
+                     base::WeakPtr<BlobStorageContext> context,
                      network::mojom::URLLoaderFactoryRequest request);
 
   // Creates a factory for a BlobURLToken. The token is used to look up the blob
diff --git a/storage/browser/blob/blob_url_store_impl.cc b/storage/browser/blob/blob_url_store_impl.cc
index c3563efb..3bbff15 100644
--- a/storage/browser/blob/blob_url_store_impl.cc
+++ b/storage/browser/blob/blob_url_store_impl.cc
@@ -19,18 +19,17 @@
  public:
   BlobURLTokenImpl(base::WeakPtr<BlobStorageContext> context,
                    const GURL& url,
-                   std::unique_ptr<BlobDataHandle> blob,
+                   mojo::PendingRemote<blink::mojom::Blob> blob,
                    mojo::PendingReceiver<blink::mojom::BlobURLToken> receiver)
       : context_(std::move(context)),
         url_(url),
-        blob_(std::move(blob)),
         token_(base::UnguessableToken::Create()) {
     receivers_.Add(this, std::move(receiver));
     receivers_.set_disconnect_handler(base::BindRepeating(
         &BlobURLTokenImpl::OnConnectionError, base::Unretained(this)));
     if (context_) {
       context_->mutable_registry()->AddTokenMapping(token_, url_,
-                                                    blob_->uuid());
+                                                    std::move(blob));
     }
   }
 
@@ -58,7 +57,6 @@
   base::WeakPtr<BlobStorageContext> context_;
   mojo::ReceiverSet<blink::mojom::BlobURLToken> receivers_;
   const GURL url_;
-  const std::unique_ptr<BlobDataHandle> blob_;
   const base::UnguessableToken token_;
 };
 
@@ -99,11 +97,10 @@
     return;
   }
 
-  mojo::Remote<blink::mojom::Blob> blob_remote(std::move(blob));
-  blink::mojom::Blob* blob_ptr = blob_remote.get();
-  blob_ptr->GetInternalUUID(base::BindOnce(
-      &BlobURLStoreImpl::RegisterWithUUID, weak_ptr_factory_.GetWeakPtr(),
-      std::move(blob_remote), url, std::move(callback)));
+  if (context_)
+    context_->RegisterPublicBlobURL(url, std::move(blob));
+  urls_.insert(url);
+  std::move(callback).Run();
 }
 
 void BlobURLStoreImpl::Revoke(const GURL& url) {
@@ -136,12 +133,8 @@
     std::move(callback).Run(mojo::NullRemote());
     return;
   }
-  mojo::PendingRemote<blink::mojom::Blob> blob;
-  std::unique_ptr<BlobDataHandle> blob_handle =
-      context_->GetBlobDataFromPublicURL(url);
-  if (blob_handle)
-    BlobImpl::Create(std::move(blob_handle),
-                     blob.InitWithNewPipeAndPassReceiver());
+  mojo::PendingRemote<blink::mojom::Blob> blob =
+      context_->GetBlobFromPublicURL(url);
   std::move(callback).Run(std::move(blob));
 }
 
@@ -149,8 +142,8 @@
     const GURL& url,
     network::mojom::URLLoaderFactoryRequest request) {
   BlobURLLoaderFactory::Create(
-      context_ ? context_->GetBlobDataFromPublicURL(url) : nullptr, url,
-      std::move(request));
+      context_ ? context_->GetBlobFromPublicURL(url) : mojo::NullRemote(), url,
+      context_, std::move(request));
 }
 
 void BlobURLStoreImpl::ResolveForNavigation(
@@ -158,23 +151,11 @@
     mojo::PendingReceiver<blink::mojom::BlobURLToken> token) {
   if (!context_)
     return;
-  std::unique_ptr<BlobDataHandle> blob_handle =
-      context_->GetBlobDataFromPublicURL(url);
-  if (!blob_handle)
+  mojo::PendingRemote<blink::mojom::Blob> blob =
+      context_->GetBlobFromPublicURL(url);
+  if (!blob)
     return;
-  new BlobURLTokenImpl(context_, url, std::move(blob_handle), std::move(token));
-}
-
-void BlobURLStoreImpl::RegisterWithUUID(mojo::Remote<blink::mojom::Blob> blob,
-                                        const GURL& url,
-                                        RegisterCallback callback,
-                                        const std::string& uuid) {
-  // |blob| is unused, but is passed here to be kept alive until
-  // RegisterPublicBlobURL increments the refcount of it via the uuid.
-  if (context_)
-    context_->RegisterPublicBlobURL(url, uuid);
-  urls_.insert(url);
-  std::move(callback).Run();
+  new BlobURLTokenImpl(context_, url, std::move(blob), std::move(token));
 }
 
 }  // namespace storage
diff --git a/storage/browser/blob/blob_url_store_impl.h b/storage/browser/blob/blob_url_store_impl.h
index 910b5a63..9565d76 100644
--- a/storage/browser/blob/blob_url_store_impl.h
+++ b/storage/browser/blob/blob_url_store_impl.h
@@ -37,11 +37,6 @@
       mojo::PendingReceiver<blink::mojom::BlobURLToken> token) override;
 
  private:
-  void RegisterWithUUID(mojo::Remote<blink::mojom::Blob> blob,
-                        const GURL& url,
-                        RegisterCallback callback,
-                        const std::string& uuid);
-
   base::WeakPtr<BlobStorageContext> context_;
   BlobRegistryImpl::Delegate* delegate_;
 
diff --git a/storage/browser/blob/blob_url_store_impl_unittest.cc b/storage/browser/blob/blob_url_store_impl_unittest.cc
index a4f785a..06a6e8b 100644
--- a/storage/browser/blob/blob_url_store_impl_unittest.cc
+++ b/storage/browser/blob/blob_url_store_impl_unittest.cc
@@ -121,16 +121,16 @@
   BlobURLStoreImpl url_store(context_->AsWeakPtr(), &delegate_);
   RegisterURL(&url_store, std::move(blob), kValidUrl);
 
-  std::unique_ptr<BlobDataHandle> blob_data_handle =
-      context_->GetBlobDataFromPublicURL(kValidUrl);
-  ASSERT_TRUE(blob_data_handle);
-  EXPECT_EQ(kId, blob_data_handle->uuid());
-  blob_data_handle = nullptr;
+  blob = context_->GetBlobFromPublicURL(kValidUrl);
+  ASSERT_TRUE(blob);
+  mojo::Remote<blink::mojom::Blob> blob_remote(std::move(blob));
+  EXPECT_EQ(kId, UUIDFromBlob(blob_remote.get()));
+  blob_remote.reset();
 
   // Revoke the URL.
   url_store.Revoke(kValidUrl);
-  blob_data_handle = context_->GetBlobDataFromPublicURL(kValidUrl);
-  EXPECT_FALSE(blob_data_handle);
+  blob = context_->GetBlobFromPublicURL(kValidUrl);
+  EXPECT_FALSE(blob);
 
   base::RunLoop().RunUntilIdle();
   EXPECT_FALSE(context_->registry().HasEntry(kId));
@@ -142,7 +142,7 @@
 
   mojo::Remote<BlobURLStore> url_store(CreateURLStore());
   RegisterURL(url_store.get(), std::move(blob), kInvalidUrl);
-  EXPECT_FALSE(context_->GetBlobDataFromPublicURL(kInvalidUrl));
+  EXPECT_FALSE(context_->GetBlobFromPublicURL(kInvalidUrl));
   EXPECT_EQ(1u, bad_messages_.size());
 }
 
@@ -154,7 +154,7 @@
 
   mojo::Remote<BlobURLStore> url_store(CreateURLStore());
   RegisterURL(url_store.get(), std::move(blob), kValidUrl);
-  EXPECT_FALSE(context_->GetBlobDataFromPublicURL(kValidUrl));
+  EXPECT_FALSE(context_->GetBlobFromPublicURL(kValidUrl));
   EXPECT_EQ(1u, bad_messages_.size());
 }
 
@@ -164,7 +164,7 @@
 
   mojo::Remote<BlobURLStore> url_store(CreateURLStore());
   RegisterURL(url_store.get(), std::move(blob), kFragmentUrl);
-  EXPECT_FALSE(context_->GetBlobDataFromPublicURL(kFragmentUrl));
+  EXPECT_FALSE(context_->GetBlobFromPublicURL(kFragmentUrl));
   EXPECT_EQ(1u, bad_messages_.size());
 }
 
@@ -178,14 +178,14 @@
   auto url_store =
       std::make_unique<BlobURLStoreImpl>(context_->AsWeakPtr(), &delegate_);
   RegisterURL(url_store.get(), blob.Unbind(), kValidUrl);
-  EXPECT_TRUE(context_->GetBlobDataFromPublicURL(kValidUrl));
+  EXPECT_TRUE(context_->GetBlobFromPublicURL(kValidUrl));
   RegisterURL(url_store.get(), std::move(blob2), kValidUrl2);
-  EXPECT_TRUE(context_->GetBlobDataFromPublicURL(kValidUrl2));
+  EXPECT_TRUE(context_->GetBlobFromPublicURL(kValidUrl2));
 
   // Destroy URL Store, should revoke URLs.
   url_store = nullptr;
-  EXPECT_FALSE(context_->GetBlobDataFromPublicURL(kValidUrl));
-  EXPECT_FALSE(context_->GetBlobDataFromPublicURL(kValidUrl2));
+  EXPECT_FALSE(context_->GetBlobFromPublicURL(kValidUrl));
+  EXPECT_FALSE(context_->GetBlobFromPublicURL(kValidUrl2));
 }
 
 TEST_F(BlobURLStoreImplTest, RevokeThroughDifferentURLStore) {
@@ -196,10 +196,10 @@
   BlobURLStoreImpl url_store2(context_->AsWeakPtr(), &delegate_);
 
   RegisterURL(&url_store1, std::move(blob), kValidUrl);
-  EXPECT_TRUE(context_->GetBlobDataFromPublicURL(kValidUrl));
+  EXPECT_TRUE(context_->GetBlobFromPublicURL(kValidUrl));
 
   url_store2.Revoke(kValidUrl);
-  EXPECT_FALSE(context_->GetBlobDataFromPublicURL(kValidUrl));
+  EXPECT_FALSE(context_->GetBlobFromPublicURL(kValidUrl));
 }
 
 TEST_F(BlobURLStoreImplTest, RevokeInvalidScheme) {
@@ -226,7 +226,7 @@
   url_store->Revoke(kValidUrl);
   url_store.FlushForTesting();
   EXPECT_TRUE(bad_messages_.empty());
-  EXPECT_FALSE(context_->GetBlobDataFromPublicURL(kValidUrl));
+  EXPECT_FALSE(context_->GetBlobFromPublicURL(kValidUrl));
 }
 
 TEST_F(BlobURLStoreImplTest, RevokeURLWithFragment) {
@@ -318,11 +318,10 @@
   loop.Run();
 
   GURL blob_url;
-  std::string blob_uuid;
-  EXPECT_TRUE(
-      context_->registry().GetTokenMapping(token, &blob_url, &blob_uuid));
+  EXPECT_TRUE(context_->registry().GetTokenMapping(token, &blob_url, &blob));
   EXPECT_EQ(kValidUrl, blob_url);
-  EXPECT_EQ(kId, blob_uuid);
+  mojo::Remote<blink::mojom::Blob> blob_remote(std::move(blob));
+  EXPECT_EQ(kId, UUIDFromBlob(blob_remote.get()));
 }
 
 }  // namespace storage
diff --git a/storage/browser/blob/view_blob_internals_job.cc b/storage/browser/blob/view_blob_internals_job.cc
index bb0fe8688..d6dca3e 100644
--- a/storage/browser/blob/view_blob_internals_job.cc
+++ b/storage/browser/blob/view_blob_internals_job.cc
@@ -44,7 +44,6 @@
 const char kModificationTime[] = "Modification Time: ";
 const char kOffset[] = "Offset: ";
 const char kLength[] = "Length: ";
-const char kUUID[] = "Uuid: ";
 const char kRefcount[] = "Refcount: ";
 const char kStatus[] = "Status: ";
 
@@ -156,14 +155,13 @@
                               entry->content_disposition(), entry->refcount(),
                               &out);
     }
-    if (!blob_storage_context->registry().url_to_uuid_.empty()) {
+    if (!blob_storage_context->registry().url_to_blob_.empty()) {
       AddHorizontalRule(&out);
       for (const auto& url_uuid_pair :
-           blob_storage_context->registry().url_to_uuid_) {
+           blob_storage_context->registry().url_to_blob_) {
         AddHTMLBoldText(url_uuid_pair.first.spec(), &out);
-        StartHTMLList(&out);
-        AddHTMLListItem(kUUID, url_uuid_pair.second, &out);
-        EndHTMLList(&out);
+        // TODO(mek): Somehow include information on the blob the URL is mapped
+        // to.
       }
     }
   }
diff --git a/testing/buildbot/chrome.json b/testing/buildbot/chrome.json
index 063870e..05fdc25 100644
--- a/testing/buildbot/chrome.json
+++ b/testing/buildbot/chrome.json
@@ -919,6 +919,9 @@
         "test": "ozone_gl_unittests"
       },
       {
+        "args": [
+          "--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.ozone_unittests.filter"
+        ],
         "merge": {
           "args": [],
           "script": "//testing/merge_scripts/standard_gtest_merge.py"
diff --git a/testing/buildbot/chromium.android.json b/testing/buildbot/chromium.android.json
index 71e20a0..f10dbdf 100644
--- a/testing/buildbot/chromium.android.json
+++ b/testing/buildbot/chromium.android.json
@@ -1273,8 +1273,7 @@
       {
         "args": [
           "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/android.webview_instrumentation_tests_oreo.filter"
+          "--recover-devices"
         ],
         "merge": {
           "args": [
@@ -1321,8 +1320,7 @@
         "args": [
           "--disable-field-trials",
           "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--test-launcher-filter-file=../../testing/buildbot/filters/android.webview_instrumentation_tests_oreo.filter"
+          "--recover-devices"
         ],
         "merge": {
           "args": [
@@ -1706,8 +1704,7 @@
       {
         "args": [
           "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--gtest-filter=-org.chromium.android_webview.test.AwAutofillTest.testJavascriptNotTriggerSelectControlChangeNotification"
+          "--recover-devices"
         ],
         "merge": {
           "args": [
@@ -1754,8 +1751,7 @@
         "args": [
           "--disable-field-trials",
           "--gs-results-bucket=chromium-result-details",
-          "--recover-devices",
-          "--gtest-filter=-org.chromium.android_webview.test.AwAutofillTest.testJavascriptNotTriggerSelectControlChangeNotification"
+          "--recover-devices"
         ],
         "merge": {
           "args": [
diff --git a/testing/buildbot/filters/BUILD.gn b/testing/buildbot/filters/BUILD.gn
index b70cf3e..ac7d8c42 100644
--- a/testing/buildbot/filters/BUILD.gn
+++ b/testing/buildbot/filters/BUILD.gn
@@ -172,7 +172,6 @@
   testonly = true
 
   data = [
-    "//testing/buildbot/filters/android.webview_instrumentation_tests_oreo.filter",
     "//testing/buildbot/filters/mojo.fyi.network_webview_instrumentation_test_apk.filter",
   ]
 }
diff --git a/testing/buildbot/filters/android.webview_instrumentation_tests_oreo.filter b/testing/buildbot/filters/android.webview_instrumentation_tests_oreo.filter
deleted file mode 100644
index c279cf1..0000000
--- a/testing/buildbot/filters/android.webview_instrumentation_tests_oreo.filter
+++ /dev/null
@@ -1 +0,0 @@
--org.chromium.android_webview.test.AwAutofillTest.testJavascriptNotTriggerSelectControlChangeNotification
diff --git a/testing/buildbot/test_suite_exceptions.pyl b/testing/buildbot/test_suite_exceptions.pyl
index ff5c0bc..af4c1cb 100644
--- a/testing/buildbot/test_suite_exceptions.pyl
+++ b/testing/buildbot/test_suite_exceptions.pyl
@@ -19,7 +19,6 @@
   'android_webview_unittests': {
     'remove_from': [
       # On chromium.android, these do not need to run prior to M.
-      'android-kitkat-arm-coverage-rel',
       'android-kitkat-arm-rel',
       'KitKat Phone Tester (dbg)',
       'KitKat Tablet Tester',
@@ -282,11 +281,6 @@
     ],
     'modifications': {
       # chromium.android
-      'android-kitkat-arm-coverage-rel': {
-        'swarming': {
-          'shards': 12,
-        }
-      },
       'KitKat Phone Tester (dbg)': {
         'swarming': {
           'shards': 20,
@@ -1036,7 +1030,6 @@
       # chromium.android
       'android-asan',
       # Don't run on trybots; waterfall is enough.
-      'android-kitkat-arm-coverage-rel',
       'android-kitkat-arm-rel',
       'android-marshmallow-arm64-coverage-rel',
       'android-marshmallow-arm64-rel',
@@ -1051,7 +1044,6 @@
       # chromium.android
       'android-asan',
       # Don't run on trybots; waterfall is enough.
-      'android-kitkat-arm-coverage-rel',
       'android-kitkat-arm-rel',
       'android-marshmallow-arm64-coverage-rel',
       'android-marshmallow-arm64-rel',
@@ -1066,7 +1058,6 @@
       # chromium.android
       'android-asan',
       # Don't run on trybots; waterfall is enough.
-      'android-kitkat-arm-coverage-rel',
       'android-kitkat-arm-rel',
       'android-marshmallow-arm64-coverage-rel',
       'android-marshmallow-arm64-rel',
@@ -1088,7 +1079,6 @@
       # chromium.android
       'android-asan',
       # Don't run on trybots; waterfall is enough.
-      'android-kitkat-arm-coverage-rel',
       'android-kitkat-arm-rel',
       'android-marshmallow-arm64-coverage-rel',
       'android-marshmallow-arm64-rel',
@@ -1102,7 +1092,6 @@
     # Only run these on the phone testers for now due to capacity.
     'remove_from': [
       # chromium.android
-      'android-kitkat-arm-coverage-rel',
       'android-kitkat-arm-rel',
       'android-marshmallow-arm64-coverage-rel',
       'android-marshmallow-arm64-rel',
@@ -1217,6 +1206,11 @@
           '--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.ozone_unittests.filter',
         ],
       },
+      'chromeos-betty-pi-arc-google-rel': {
+        'args': [
+          '--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.ozone_unittests.filter',
+        ],
+      },
       'linux-chromeos-google-rel': {
         'args': [
           '--test-launcher-filter-file=../../testing/buildbot/filters/chromeos.ozone_unittests.filter',
@@ -1228,7 +1222,6 @@
     'remove_from': [
       'android-asan',
       'android-code-coverage',
-      'android-kitkat-arm-coverage-rel',
       'android-kitkat-arm-rel',
       'android-marshmallow-arm64-coverage-rel',
       'android-marshmallow-arm64-rel',
@@ -1428,20 +1421,6 @@
   'telemetry_perf_unittests': {
     'modifications': {
       # chromium.android
-      'android-kitkat-arm-coverage-rel': {
-        'args': [
-          '--browser=android-chromium',
-          '--device=android',
-        ],
-        'swarming': {
-          'dimension_sets': [
-            {
-              'temp_band': '<30',
-            },
-          ],
-          'shards': 15,
-        },
-      },
       'android-kitkat-arm-rel': {
         'args': [
           '--browser=android-chromium',
@@ -2021,7 +2000,6 @@
     'remove_from': [
       # This test frequently fails on Android, https://crbug.com/824959
       # chromium.android
-      'android-kitkat-arm-coverage-rel',
       'android-kitkat-arm-rel',
       'KitKat Phone Tester (dbg)',
       'KitKat Tablet Tester',
@@ -2041,34 +2019,6 @@
         # either passing or there is more capacity.
         'experiment_percentage': 0,
       },
-      'Android WebView O (dbg)': {
-        #TODO(crbug.com/997362): Remove test filters once bug is resolved.
-        'args': [
-          '--test-launcher-filter-file=../../testing/buildbot/filters/android.webview_instrumentation_tests_oreo.filter',
-        ],
-      },
-      'Android WebView P (dbg)': {
-        #TODO(crbug.com/1001309): Remove test filters once bug is resolved.
-        'args': [
-          '--gtest-filter=-org.chromium.android_webview.test.AwAutofillTest.testJavascriptNotTriggerSelectControlChangeNotification',
-        ],
-      },
-    },
-  },
-  'webview_instrumentation_test_apk_no_field_trial': {
-    'modifications': {
-      'Android WebView O (dbg)': {
-        #TODO(crbug.com/997362): Remove test filters once bug is resolved.
-        'args': [
-          '--test-launcher-filter-file=../../testing/buildbot/filters/android.webview_instrumentation_tests_oreo.filter',
-        ],
-      },
-      'Android WebView P (dbg)': {
-        #TODO(crbug.com/1001309): Remove test filters once bug is resolved.
-        'args': [
-          '--gtest-filter=-org.chromium.android_webview.test.AwAutofillTest.testJavascriptNotTriggerSelectControlChangeNotification',
-        ],
-      },
     },
   },
   'xr_browser_tests': {
diff --git a/testing/buildbot/tryserver.chromium.android.json b/testing/buildbot/tryserver.chromium.android.json
index ec9ca73..dd5397f 100644
--- a/testing/buildbot/tryserver.chromium.android.json
+++ b/testing/buildbot/tryserver.chromium.android.json
@@ -1,3024 +1,6 @@
 {
   "AAAAA1 AUTOGENERATED FILE DO NOT EDIT": {},
   "AAAAA2 See generate_buildbot_json.py to make changes": {},
-  "android-kitkat-arm-coverage-rel": {
-    "additional_compile_targets": [
-      "cronet_test_instrumentation_apk",
-      "monochrome_static_initializers"
-    ],
-    "gtest_tests": [
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "android_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "android_browsertests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "angle_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "angle_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "base_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "base_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "base_util_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "base_util_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "blink_common_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "blink_common_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "blink_heap_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "blink_heap_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "blink_platform_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "blink_platform_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "webkit_unit_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "name": "webkit_unit_tests",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "shards": 2
-        },
-        "test": "blink_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "boringssl_crypto_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "boringssl_crypto_tests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "boringssl_ssl_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "boringssl_ssl_tests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "breakpad_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "breakpad_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "cacheinvalidation_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "cacheinvalidation_unittests"
-      },
-      {
-        "args": [
-          "--gtest_filter=-*UsingRealWebcam*",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "capture_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "capture_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "cast_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "cast_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "cc_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "cc_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "chrome_public_smoke_test"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "chrome_public_smoke_test"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "chrome_public_test_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "shards": 12
-        },
-        "test": "chrome_public_test_apk"
-      },
-      {
-        "args": [
-          "--shared-prefs-file=//chrome/android/shared_preference_files/test/vr_cardboard_skipdon_setupcomplete.json",
-          "--additional-apk=//third_party/gvr-android-sdk/test-apks/vr_services/vr_services_current.apk",
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "chrome_public_test_vr_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "shards": 2
-        },
-        "test": "chrome_public_test_vr_apk"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "color_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "color_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "components_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "components_browsertests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "components_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "shards": 4
-        },
-        "test": "components_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "content_browsertests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "shards": 9
-        },
-        "test": "content_browsertests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "content_shell_test_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "shards": 3
-        },
-        "test": "content_shell_test_apk"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "content_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "shards": 3
-        },
-        "test": "content_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "crypto_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "crypto_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "device_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "device_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "display_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "display_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "events_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "events_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gcm_unit_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "gcm_unit_tests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gfx_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "gfx_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gin_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "gin_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gl_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "gl_tests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gl_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "gl_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "google_apis_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "google_apis_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gpu_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "gpu_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "gwp_asan_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "gwp_asan_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ipc_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "ipc_tests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "jingle_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "jingle_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "latency_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "latency_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "libjingle_xmpp_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "libjingle_xmpp_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "media_blink_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "media_blink_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "media_service_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "media_service_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "media_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "media_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "midi_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "midi_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "mojo_test_apk"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "mojo_test_apk"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "mojo_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "mojo_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "net_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "shards": 3
-        },
-        "test": "net_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "sandbox_linux_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "sandbox_linux_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "services_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "services_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "shell_dialogs_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "shell_dialogs_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "skia_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "skia_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "sql_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "sql_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "storage_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "storage_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ui_android_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "ui_android_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ui_base_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "ui_base_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "ui_touch_selection_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "ui_touch_selection_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "unit_tests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ],
-          "shards": 10
-        },
-        "test": "unit_tests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "url_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "url_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "viz_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "viz_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "vr_android_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "vr_android_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "vr_common_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "vr_common_unittests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "vr_pixeltests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "vr_pixeltests"
-      },
-      {
-        "args": [
-          "--gs-results-bucket=chromium-result-details",
-          "--recover-devices"
-        ],
-        "isolate_coverage_data": true,
-        "merge": {
-          "args": [
-            "--bucket",
-            "chromium-result-details",
-            "--test-name",
-            "wtf_unittests"
-          ],
-          "script": "//build/android/pylib/results/presentation/test_results_presentation.py"
-        },
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "cipd_packages": [
-            {
-              "cipd_package": "infra/tools/luci/logdog/butler/${platform}",
-              "location": "bin",
-              "revision": "git_revision:ff387eadf445b24c935f1cf7d6ddd279f8a6b04c"
-            }
-          ],
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ],
-          "output_links": [
-            {
-              "link": [
-                "https://luci-logdog.appspot.com/v/?s",
-                "=android%2Fswarming%2Flogcats%2F",
-                "${TASK_ID}%2F%2B%2Funified_logcats"
-              ],
-              "name": "shard #${SHARD_INDEX} logcats"
-            }
-          ]
-        },
-        "test": "wtf_unittests"
-      }
-    ],
-    "isolated_scripts": [
-      {
-        "isolate_coverage_data": true,
-        "isolate_name": "monochrome_apk_checker",
-        "merge": {
-          "args": [],
-          "script": "//testing/merge_scripts/standard_isolated_script_merge.py"
-        },
-        "name": "monochrome_apk_checker",
-        "swarming": {
-          "can_use_on_swarming_builders": true,
-          "dimension_sets": [
-            {
-              "device_os": "KTU84P",
-              "device_os_type": "userdebug",
-              "device_type": "hammerhead",
-              "os": "Android"
-            }
-          ]
-        }
-      }
-    ],
-    "junit_tests": [
-      {
-        "isolate_coverage_data": true,
-        "name": "android_webview_junit_tests",
-        "swarming": {},
-        "test": "android_webview_junit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "base_junit_tests",
-        "swarming": {},
-        "test": "base_junit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "chrome_junit_tests",
-        "swarming": {},
-        "test": "chrome_junit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "components_background_task_scheduler_junit_tests",
-        "swarming": {},
-        "test": "components_background_task_scheduler_junit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "components_gcm_driver_junit_tests",
-        "swarming": {},
-        "test": "components_gcm_driver_junit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "components_invalidation_impl_junit_tests",
-        "swarming": {},
-        "test": "components_invalidation_impl_junit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "components_policy_junit_tests",
-        "swarming": {},
-        "test": "components_policy_junit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "components_signin_junit_tests",
-        "swarming": {},
-        "test": "components_signin_junit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "components_variations_junit_tests",
-        "swarming": {},
-        "test": "components_variations_junit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "content_junit_tests",
-        "swarming": {},
-        "test": "content_junit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "device_junit_tests",
-        "swarming": {},
-        "test": "device_junit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "junit_unit_tests",
-        "swarming": {},
-        "test": "junit_unit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "keyboard_accessory_junit_tests",
-        "swarming": {},
-        "test": "keyboard_accessory_junit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "media_base_junit_tests",
-        "swarming": {},
-        "test": "media_base_junit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "media_router_junit_tests",
-        "swarming": {},
-        "test": "media_router_junit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "module_installer_junit_tests",
-        "swarming": {},
-        "test": "module_installer_junit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "net_junit_tests",
-        "swarming": {},
-        "test": "net_junit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "service_junit_tests",
-        "swarming": {},
-        "test": "service_junit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "touch_to_fill_junit_tests",
-        "swarming": {},
-        "test": "touch_to_fill_junit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "ui_junit_tests",
-        "swarming": {},
-        "test": "ui_junit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "webapk_client_junit_tests",
-        "swarming": {},
-        "test": "webapk_client_junit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "webapk_shell_apk_h2o_junit_tests",
-        "swarming": {},
-        "test": "webapk_shell_apk_h2o_junit_tests"
-      },
-      {
-        "isolate_coverage_data": true,
-        "name": "webapk_shell_apk_junit_tests",
-        "swarming": {},
-        "test": "webapk_shell_apk_junit_tests"
-      }
-    ]
-  },
   "android-marshmallow-arm64-coverage-rel": {
     "additional_compile_targets": [
       "monochrome_static_initializers",
diff --git a/testing/buildbot/waterfalls.pyl b/testing/buildbot/waterfalls.pyl
index 56001b981..c5ccba3 100644
--- a/testing/buildbot/waterfalls.pyl
+++ b/testing/buildbot/waterfalls.pyl
@@ -4377,23 +4377,6 @@
   {
     'name': 'tryserver.chromium.android',
     'machines': {
-      'android-kitkat-arm-coverage-rel': {
-        'mixins': [
-          'code-coverage',
-          'kitkat',
-          'hammerhead',
-        ],
-        'additional_compile_targets': [
-          'cronet_test_instrumentation_apk',
-          'monochrome_static_initializers',
-        ],
-        'test_suites': {
-          'gtest_tests': 'chromium_android_gtests',
-          'junit_tests': 'chromium_junit_tests',
-          'isolated_scripts': 'monochrome_apk_checker_isolated_script',
-        },
-        'os_type': 'android',
-      },
       'android-marshmallow-arm64-coverage-rel': {
         'mixins': [
           'code-coverage',
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
index 95316c38..95b561b3 100644
--- a/third_party/blink/common/features.cc
+++ b/third_party/blink/common/features.cc
@@ -64,13 +64,7 @@
 // a mask layer.
 const base::Feature kFastBorderRadius {
   "FastBorderRadius",
-#if defined(OS_MACOSX)
-      // A FastBorderRadiusMac experiment is rolling out separately for that
-      // platform, due to complications with CALayer overlay optimizations.
-      base::FEATURE_DISABLED_BY_DEFAULT
-#else
       base::FEATURE_ENABLED_BY_DEFAULT
-#endif
 };
 
 // Enable LayoutNG.
diff --git a/third_party/blink/common/loader/mime_sniffing_throttle_unittest.cc b/third_party/blink/common/loader/mime_sniffing_throttle_unittest.cc
index 4b68cf0..9c7d7bff 100644
--- a/third_party/blink/common/loader/mime_sniffing_throttle_unittest.cc
+++ b/third_party/blink/common/loader/mime_sniffing_throttle_unittest.cc
@@ -325,7 +325,7 @@
   // The mime type should be updated to the default mime type ("text/plain").
   EXPECT_TRUE(delegate->destination_loader_client()->has_received_response());
   EXPECT_EQ("text/plain",
-            delegate->destination_loader_client()->response_head().mime_type);
+            delegate->destination_loader_client()->response_head()->mime_type);
 }
 
 TEST_F(MimeSniffingThrottleTest, EmptyBody) {
@@ -355,7 +355,7 @@
   // The mime type should be updated to the default mime type ("text/plain").
   EXPECT_TRUE(delegate->destination_loader_client()->has_received_response());
   EXPECT_EQ("text/plain",
-            delegate->destination_loader_client()->response_head().mime_type);
+            delegate->destination_loader_client()->response_head()->mime_type);
 }
 
 TEST_F(MimeSniffingThrottleTest, Body_PlainText) {
@@ -379,7 +379,7 @@
   // The mime type should be updated.
   EXPECT_TRUE(delegate->is_resumed());
   EXPECT_EQ("text/plain",
-            delegate->destination_loader_client()->response_head().mime_type);
+            delegate->destination_loader_client()->response_head()->mime_type);
 }
 
 TEST_F(MimeSniffingThrottleTest, Body_Docx) {
@@ -403,7 +403,7 @@
   // The mime type should be updated.
   EXPECT_TRUE(delegate->is_resumed());
   EXPECT_EQ("application/msword",
-            delegate->destination_loader_client()->response_head().mime_type);
+            delegate->destination_loader_client()->response_head()->mime_type);
 }
 
 TEST_F(MimeSniffingThrottleTest, Body_PNG) {
@@ -427,7 +427,7 @@
   // The mime type should be updated.
   EXPECT_TRUE(delegate->is_resumed());
   EXPECT_EQ("image/png",
-            delegate->destination_loader_client()->response_head().mime_type);
+            delegate->destination_loader_client()->response_head()->mime_type);
 }
 
 TEST_F(MimeSniffingThrottleTest, Body_LongPlainText) {
@@ -483,7 +483,7 @@
   // The mime type should be updated.
   EXPECT_TRUE(delegate->is_resumed());
   EXPECT_EQ("text/plain",
-            delegate->destination_loader_client()->response_head().mime_type);
+            delegate->destination_loader_client()->response_head()->mime_type);
 }
 
 TEST_F(MimeSniffingThrottleTest, Abort_NoBodyPipe) {
diff --git a/third_party/blink/public/mojom/fetch/fetch_api_response.mojom b/third_party/blink/public/mojom/fetch/fetch_api_response.mojom
index 622e84b..34ea2a4 100644
--- a/third_party/blink/public/mojom/fetch/fetch_api_response.mojom
+++ b/third_party/blink/public/mojom/fetch/fetch_api_response.mojom
@@ -6,6 +6,7 @@
 
 import "mojo/public/mojom/base/time.mojom";
 import "services/network/public/mojom/fetch_api.mojom";
+import "services/network/public/mojom/content_security_policy.mojom";
 import "third_party/blink/public/mojom/blob/serialized_blob.mojom";
 import "third_party/blink/public/mojom/service_worker/service_worker_error_type.mojom";
 import "url/mojom/url.mojom";
@@ -61,4 +62,8 @@
 
   // Side data is used to pass the metadata of the response (eg. V8 code cache).
   SerializedBlob? side_data_blob;
+
+  // In case this response had a Content-Security-Policy header, this is the
+  // parsed CSP.
+  network.mojom.ContentSecurityPolicy? content_security_policy;
 };
diff --git a/third_party/blink/public/mojom/service_worker/embedded_worker.mojom b/third_party/blink/public/mojom/service_worker/embedded_worker.mojom
index 9433fee..69c71f4 100644
--- a/third_party/blink/public/mojom/service_worker/embedded_worker.mojom
+++ b/third_party/blink/public/mojom/service_worker/embedded_worker.mojom
@@ -47,8 +47,9 @@
   // The string used for "user-agent" HTTP header.
   string user_agent;
 
-  // The id to talk with the DevTools agent for the worker.
-  int32 worker_devtools_agent_route_id;
+  // The id this service worker uses as render_frame_id in
+  // network::ResourceRequests it makes.
+  int32 service_worker_route_id;
 
   // Unique token identifying this worker for DevTools.
   mojo_base.mojom.UnguessableToken devtools_worker_token;
diff --git a/third_party/blink/public/mojom/web_feature/web_feature.mojom b/third_party/blink/public/mojom/web_feature/web_feature.mojom
index cfbf2b2..8cf8adb 100644
--- a/third_party/blink/public/mojom/web_feature/web_feature.mojom
+++ b/third_party/blink/public/mojom/web_feature/web_feature.mojom
@@ -2416,6 +2416,7 @@
   kThirdPartyBroadcastChannel = 3033,
   kMediaSourceGroupEndTimestampDecreaseWithinMediaSegment = 3034,
   kTextFragmentAnchorTapToDismiss = 3035,
+  kXRIsSessionSupported = 3036,
 
   // Add new features immediately above this line. Don't change assigned
   // numbers of any item, and don't reuse removed slots.
diff --git a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc
index 0b0da0c..240e1b3 100644
--- a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc
+++ b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_deserializer.cc
@@ -509,7 +509,8 @@
           !ReadUint32(&canvas_id) || !ReadUint32(&client_id) ||
           !ReadUint32(&sink_id))
         return nullptr;
-      OffscreenCanvas* canvas = OffscreenCanvas::Create(width, height);
+      OffscreenCanvas* canvas = OffscreenCanvas::Create(
+          ExecutionContext::From(GetScriptState()), width, height);
       canvas->SetPlaceholderCanvasId(canvas_id);
       canvas->SetFrameSinkId(client_id, sink_id);
       return canvas;
diff --git a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc
index c53a9f9..7443dc9 100644
--- a/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc
+++ b/third_party/blink/renderer/bindings/core/v8/serialization/v8_script_value_serializer_test.cc
@@ -1293,7 +1293,8 @@
 TEST(V8ScriptValueSerializerTest, TransferOffscreenCanvas) {
   // More exhaustive tests in web_tests/. This is a sanity check.
   V8TestingScope scope;
-  OffscreenCanvas* canvas = OffscreenCanvas::Create(10, 7);
+  OffscreenCanvas* canvas =
+      OffscreenCanvas::Create(scope.GetExecutionContext(), 10, 7);
   canvas->SetPlaceholderCanvasId(519);
   v8::Local<v8::Value> wrapper = ToV8(canvas, scope.GetScriptState());
   Transferables transferables;
diff --git a/third_party/blink/renderer/core/animation/BUILD.gn b/third_party/blink/renderer/core/animation/BUILD.gn
index 824fe595..269d1b3 100644
--- a/third_party/blink/renderer/core/animation/BUILD.gn
+++ b/third_party/blink/renderer/core/animation/BUILD.gn
@@ -152,12 +152,12 @@
     "effect_stack.h",
     "element_animations.cc",
     "element_animations.h",
-    "filter_interpolation_functions.cc",
-    "filter_interpolation_functions.h",
     "image_list_property_functions.h",
     "image_slice_property_functions.h",
     "inert_effect.cc",
     "inert_effect.h",
+    "interpolable_filter.cc",
+    "interpolable_filter.h",
     "interpolable_length.cc",
     "interpolable_length.h",
     "interpolable_shadow.cc",
diff --git a/third_party/blink/renderer/core/animation/animation.cc b/third_party/blink/renderer/core/animation/animation.cc
index 3bf9787..7b502dc 100644
--- a/third_party/blink/renderer/core/animation/animation.cc
+++ b/third_party/blink/renderer/core/animation/animation.cc
@@ -86,6 +86,18 @@
   return value;
 }
 
+double Max(base::Optional<double> a, double b) {
+  if (a.has_value())
+    return std::max(a.value(), b);
+  return b;
+}
+
+double Min(base::Optional<double> a, double b) {
+  if (a.has_value())
+    return std::min(a.value(), b);
+  return b;
+}
+
 void RecordCompositorAnimationFailureReasons(
     CompositorAnimations::FailureReasons failure_reasons) {
   // UMA_HISTOGRAM_ENUMERATION requires that the enum_max must be strictly
@@ -271,6 +283,36 @@
     start_time_ = CalculateStartTime(new_current_time);
 }
 
+// https://drafts.csswg.org/web-animations/#setting-the-current-time-of-an-animation
+// See steps for silently setting the current time. The preliminary step of
+// handling an unresolved time are to be handled by the caller.
+void Animation::SetCurrentTimeInternal(double new_current_time) {
+  DCHECK(std::isfinite(new_current_time));
+
+  base::Optional<double> previous_start_time = start_time_;
+  base::Optional<double> previous_hold_time = hold_time_;
+
+  // Update either the hold time or the start time.
+  if (hold_time_ || !start_time_ || !timeline_ || !timeline_->IsActive() ||
+      playback_rate_ == 0)
+    hold_time_ = new_current_time;
+  else
+    start_time_ = CalculateStartTime(new_current_time);
+
+  // Preserve invariant that we can only set a start time or a hold time in the
+  // absence of an active timeline.
+  if (!timeline_ || !timeline_->IsActive())
+    start_time_ = base::nullopt;
+
+  // Reset the previous current time.
+  previous_current_time_ = base::nullopt;
+
+  if (previous_start_time != start_time_ || previous_hold_time != hold_time_)
+    SetOutdated();
+}
+
+// TODO(crbug.com/960944): Deprecate. This method is only called by methods that
+// are pending refactoring to align with the web-animation spec.
 void Animation::SetCurrentTimeInternal(double new_current_time,
                                        TimingUpdateReason reason) {
   DCHECK(std::isfinite(new_current_time));
@@ -296,6 +338,8 @@
     outdated = true;
   }
 
+  previous_current_time_ = base::nullopt;
+
   if (outdated) {
     SetOutdated();
   }
@@ -798,6 +842,7 @@
   // (https://drafts.csswg.org/web-animations/#play-states).
   paused_ = true;
   pending_pause_ = true;
+  pending_play_ = false;
 
   current_time_pending_ = true;
   SetCurrentTimeInternal(new_current_time, kTimingUpdateOnDemand);
@@ -843,6 +888,7 @@
 
   internal_play_state_ = kUnset;
   pending_play_ = true;
+  pending_pause_ = false;
   finished_ = false;
   UnpauseInternal();
 
@@ -883,40 +929,129 @@
   }
 }
 
+// ----------------------------------------------
+// Finish methods.
+// ----------------------------------------------
+
 // https://drafts.csswg.org/web-animations/#finishing-an-animation-section
 void Animation::finish(ExceptionState& exception_state) {
-  // Force resolution of PlayStateUpdateScope to enable immediate queuing of
-  // the finished event.
-  {
-    PlayStateUpdateScope update_scope(*this, kTimingUpdateOnDemand);
-
-    if (!playback_rate_) {
-      exception_state.ThrowDOMException(
-          DOMExceptionCode::kInvalidStateError,
-          "Cannot finish Animation with a playbackRate of 0.");
-      return;
-    }
-    if (playback_rate_ > 0 &&
-        EffectEnd() == std::numeric_limits<double>::infinity()) {
-      exception_state.ThrowDOMException(
-          DOMExceptionCode::kInvalidStateError,
-          "Cannot finish Animation with an infinite target effect end.");
-      return;
-    }
-
-    // Avoid updating start time when already finished.
-    if (CalculatePlayState() == kFinished)
-      return;
-
-    double new_current_time = playback_rate_ < 0 ? 0 : EffectEnd();
-    SetCurrentTimeInternal(new_current_time, kTimingUpdateOnDemand);
-    paused_ = false;
-    current_time_pending_ = false;
-    start_time_ = CalculateStartTime(new_current_time);
-    internal_play_state_ = kFinished;
-    ResetPendingTasks();
+  if (!EffectivePlaybackRate()) {
+    exception_state.ThrowDOMException(
+        DOMExceptionCode::kInvalidStateError,
+        "Cannot finish Animation with a playbackRate of 0.");
+    return;
   }
-  // Resolve finished event immediately.
+  if (EffectivePlaybackRate() > 0 &&
+      EffectEnd() == std::numeric_limits<double>::infinity()) {
+    exception_state.ThrowDOMException(
+        DOMExceptionCode::kInvalidStateError,
+        "Cannot finish Animation with an infinite target effect end.");
+    return;
+  }
+
+  ApplyPendingPlaybackRate();
+
+  double new_current_time = playback_rate_ < 0 ? 0 : EffectEnd();
+  SetCurrentTimeInternal(new_current_time);
+
+  if (!start_time_ && timeline_ && timeline_->IsActive())
+    start_time_ = CalculateStartTime(new_current_time);
+
+  if (pending_pause_ && start_time_) {
+    hold_time_ = base::nullopt;
+    pending_pause_ = false;
+    if (ready_promise_)
+      ResolvePromiseMaybeAsync(ready_promise_.Get());
+  }
+  if (pending_play_ && start_time_) {
+    pending_play_ = false;
+    if (ready_promise_)
+      ResolvePromiseMaybeAsync(ready_promise_.Get());
+  }
+
+  // TODO(crbug.com/960944): Cleanup use of legacy flags.
+  paused_ = false;
+  current_time_pending_ = false;
+  internal_play_state_ = kUnset;
+  ResetPendingTasks();
+
+  SetOutdated();
+  UpdateFinishedState(UpdateType::kDiscontinuous, NotificationType::kSync);
+  animation_play_state_ = internal_play_state_ = kFinished;
+}
+
+void Animation::UpdateFinishedState(UpdateType update_type,
+                                    NotificationType notification_type) {
+  bool did_seek = update_type == UpdateType::kDiscontinuous;
+  // 1. Calculate the unconstrained current time. The dependency on did_seek is
+  // required to accommodate timelines that may change direction. Without this
+  // distinction, a once-finished animation would remain finished even when its
+  // timeline progresses in the opposite direction.
+  double unconstrained_current_time =
+      did_seek ? CurrentTimeInternal() : CalculateCurrentTime();
+
+  // 2. Conditionally update the hold time.
+  if (!IsNull(unconstrained_current_time) && start_time_ && !pending_play_ &&
+      !pending_pause_) {
+    // Can seek outside the bounds of the active effect. Set the hold time to
+    // the unconstrained value of the current time in the even that this update
+    // this the result of explicitly setting the current time and the new time
+    // is out of bounds. An update due to a time tick should not snap the hold
+    // value back to the boundary if previously set outside the normal effect
+    // boundary. The value of previous current time is used to retain this
+    // value.
+    double playback_rate = EffectivePlaybackRate();
+    if (playback_rate > 0 && unconstrained_current_time >= EffectEnd()) {
+      hold_time_ = did_seek ? unconstrained_current_time
+                            : Max(previous_current_time_, EffectEnd());
+    } else if (playback_rate < 0 && unconstrained_current_time <= 0) {
+      hold_time_ = did_seek ? unconstrained_current_time
+                            : Min(previous_current_time_, 0);
+      // Hack for resolving precision issue at zero.
+      if (hold_time_.value() == -0)
+        hold_time_ = 0;
+    } else if (playback_rate != 0) {
+      // Update start time and reset hold time.
+      if (did_seek && hold_time_)
+        start_time_ = CalculateStartTime(hold_time_.value());
+      hold_time_ = base::nullopt;
+    }
+  }
+
+  // 3. Set the previous current time.
+  previous_current_time_ = ValueOrUnresolved(CurrentTimeInternal());
+
+  // 4. Set the current finished state.
+  AnimationPlayState play_state = CalculateAnimationPlayState();
+
+  if (play_state == kFinished) {
+    // 5. Setup finished notification.
+    if (notification_type == NotificationType::kSync) {
+      CommitFinishNotification();
+    } else {
+      // TODO(crbug.com/960944): Schedule an asynchronous notification.
+      // This code path is not currently being used as the only call site
+      // for UpdateFinishedState is from finish() which triggers a synchronous
+      // notification.
+      NOTIMPLEMENTED();
+    }
+  } else {
+    // 6. If not finished but the current finished promise is already resolved,
+    //    create a new promise.
+    finished_ = false;
+    if (finished_promise_ &&
+        finished_promise_->GetState() == AnimationPromise::kResolved) {
+      finished_promise_->Reset();
+    }
+  }
+  NotifyProbe();
+}
+
+void Animation::CommitFinishNotification() {
+  if (finished_promise_ &&
+      finished_promise_->GetState() == AnimationPromise::kPending) {
+    ResolvePromiseMaybeAsync(finished_promise_.Get());
+  }
   QueueFinishedEvent();
 }
 
@@ -1008,6 +1143,17 @@
   return active_playback_rate_.value_or(playback_rate_);
 }
 
+double Animation::EffectivePlaybackRate() const {
+  // TODO(crbug.com/960944): Use pending playback rate.
+  return playback_rate_;
+}
+
+void Animation::ApplyPendingPlaybackRate() {
+  // TODO(crbug.com/960944): If pending playback rate is set, then update the
+  // playback rate accordingly.
+  active_playback_rate_ = base::nullopt;
+}
+
 void Animation::setPlaybackRate(double playback_rate,
                                 ExceptionState& exception_state) {
   // TODO(crbug.com/916117): Implement setting playback rate for scroll-linked
diff --git a/third_party/blink/renderer/core/animation/animation.h b/third_party/blink/renderer/core/animation/animation.h
index 7980dd8..582a127d 100644
--- a/third_party/blink/renderer/core/animation/animation.h
+++ b/third_party/blink/renderer/core/animation/animation.h
@@ -257,8 +257,8 @@
   AnimationPlayState PlayStateInternal() const;
 
   double CurrentTimeInternal() const;
-  void SetCurrentTimeInternal(double new_current_time,
-                              TimingUpdateReason = kTimingUpdateOnDemand);
+  void SetCurrentTimeInternal(double new_current_time);
+  void SetCurrentTimeInternal(double new_current_time, TimingUpdateReason);
 
   void ClearOutdated();
   void ForceServiceOnNextFrame();
@@ -270,6 +270,7 @@
   // If there are no pending tasks, then the effective playback rate equals the
   // active playback rate.
   double EffectivePlaybackRate() const;
+  void ApplyPendingPlaybackRate();
   void ResolvePendingPlaybackRate();
 
   // https://drafts.csswg.org/web-animations/#play-states
@@ -316,12 +317,23 @@
   void RejectAndResetPromise(AnimationPromise*);
   void RejectAndResetPromiseMaybeAsync(AnimationPromise*);
 
+  // Updates the finished state of the animation. If the update is the result of
+  // a discontinuous time change then the value for current time is not bound by
+  // the limits of the animation. The finished notification may be synchronous
+  // or asynchronous. A synchronous notification is used in the case of
+  // explicitly calling finish on an animation.
+  enum class UpdateType { kContinuous, kDiscontinuous };
+  enum class NotificationType { kAsync, kSync };
+  void UpdateFinishedState(UpdateType update_context,
+                           NotificationType notification_type);
   void QueueFinishedEvent();
 
   void ResetPendingTasks();
   double TimelineTime() const;
   DocumentTimeline& TickingTimeline();
 
+  void CommitFinishNotification();
+
   // Tracking the state of animations in dev tools.
   void NotifyProbe();
 
@@ -349,6 +361,7 @@
   base::Optional<double> active_playback_rate_;
   base::Optional<double> start_time_;
   base::Optional<double> hold_time_;
+  base::Optional<double> previous_current_time_;
 
   unsigned sequence_number_;
 
diff --git a/third_party/blink/renderer/core/animation/animation_test.cc b/third_party/blink/renderer/core/animation/animation_test.cc
index 21a6051..236de76 100644
--- a/third_party/blink/renderer/core/animation/animation_test.cc
+++ b/third_party/blink/renderer/core/animation/animation_test.cc
@@ -623,11 +623,11 @@
 
 TEST_F(AnimationAnimationTestNoCompositing, FinishAfterEffectEnd) {
   NonThrowableExceptionState exception_state;
+  // OK to set current time out of bounds.
   animation->setCurrentTime(40000, false);
   animation->finish(exception_state);
-  // TODO(crbug/958433): This is not to spec.  Finish should trigger a snap to
-  // the upper boundary.
-  EXPECT_EQ(40000, animation->currentTime());
+  // The finish method triggers a snap to the upper boundary.
+  EXPECT_EQ(30000, animation->currentTime());
 }
 
 TEST_F(AnimationAnimationTestNoCompositing, FinishBeforeStart) {
diff --git a/third_party/blink/renderer/core/animation/css_filter_list_interpolation_type.cc b/third_party/blink/renderer/core/animation/css_filter_list_interpolation_type.cc
index 4b8b02b..310104e 100644
--- a/third_party/blink/renderer/core/animation/css_filter_list_interpolation_type.cc
+++ b/third_party/blink/renderer/core/animation/css_filter_list_interpolation_type.cc
@@ -8,7 +8,7 @@
 #include <utility>
 
 #include "base/memory/ptr_util.h"
-#include "third_party/blink/renderer/core/animation/filter_interpolation_functions.h"
+#include "third_party/blink/renderer/core/animation/interpolable_filter.h"
 #include "third_party/blink/renderer/core/animation/list_interpolation_functions.h"
 #include "third_party/blink/renderer/core/css/css_identifier_value.h"
 #include "third_party/blink/renderer/core/css/css_property_names.h"
@@ -52,28 +52,32 @@
 class UnderlyingFilterListChecker
     : public CSSInterpolationType::CSSConversionChecker {
  public:
-  UnderlyingFilterListChecker(
-      scoped_refptr<const NonInterpolableList> non_interpolable_list)
-      : non_interpolable_list_(std::move(non_interpolable_list)) {}
+  UnderlyingFilterListChecker(const InterpolableList* interpolable_list) {
+    wtf_size_t length = interpolable_list->length();
+    types_.ReserveInitialCapacity(length);
+    for (wtf_size_t i = 0; i < length; i++) {
+      types_.push_back(
+          To<InterpolableFilter>(interpolable_list->Get(i))->GetType());
+    }
+  }
 
   bool IsValid(const StyleResolverState&,
                const InterpolationValue& underlying) const final {
-    const NonInterpolableList& underlying_non_interpolable_list =
-        ToNonInterpolableList(*underlying.non_interpolable_value);
-    if (non_interpolable_list_->length() !=
-        underlying_non_interpolable_list.length())
+    const InterpolableList& underlying_list =
+        ToInterpolableList(*underlying.interpolable_value);
+    if (underlying_list.length() != types_.size())
       return false;
-    for (wtf_size_t i = 0; i < non_interpolable_list_->length(); i++) {
-      if (!filter_interpolation_functions::FiltersAreCompatible(
-              *non_interpolable_list_->Get(i),
-              *underlying_non_interpolable_list.Get(i)))
+    for (wtf_size_t i = 0; i < types_.size(); i++) {
+      FilterOperation::OperationType other_type =
+          To<InterpolableFilter>(underlying_list.Get(i))->GetType();
+      if (types_[i] != other_type)
         return false;
     }
     return true;
   }
 
  private:
-  scoped_refptr<const NonInterpolableList> non_interpolable_list_;
+  Vector<FilterOperation::OperationType> types_;
 };
 
 class InheritedFilterListChecker
@@ -101,21 +105,15 @@
                                      double zoom) {
   wtf_size_t length = filter_operations.size();
   auto interpolable_list = std::make_unique<InterpolableList>(length);
-  Vector<scoped_refptr<const NonInterpolableValue>> non_interpolable_values(
-      length);
   for (wtf_size_t i = 0; i < length; i++) {
-    InterpolationValue filter_result =
-        filter_interpolation_functions::MaybeConvertFilter(
-            *filter_operations.Operations()[i], zoom);
-    if (!filter_result)
+    std::unique_ptr<InterpolableFilter> result =
+        InterpolableFilter::MaybeCreate(*filter_operations.Operations()[i],
+                                        zoom);
+    if (!result)
       return nullptr;
-    interpolable_list->Set(i, std::move(filter_result.interpolable_value));
-    non_interpolable_values[i] =
-        std::move(filter_result.non_interpolable_value);
+    interpolable_list->Set(i, std::move(result));
   }
-  return InterpolationValue(
-      std::move(interpolable_list),
-      NonInterpolableList::Create(std::move(non_interpolable_values)));
+  return InterpolationValue(std::move(interpolable_list));
 }
 
 }  // namespace
@@ -123,13 +121,11 @@
 InterpolationValue CSSFilterListInterpolationType::MaybeConvertNeutral(
     const InterpolationValue& underlying,
     ConversionCheckers& conversion_checkers) const {
-  // const_cast for taking refs.
-  NonInterpolableList& non_interpolable_list = const_cast<NonInterpolableList&>(
-      ToNonInterpolableList(*underlying.non_interpolable_value));
+  const InterpolableList* interpolable_list =
+      ToInterpolableList(underlying.interpolable_value.get());
   conversion_checkers.push_back(
-      std::make_unique<UnderlyingFilterListChecker>(&non_interpolable_list));
-  return InterpolationValue(underlying.interpolable_value->CloneAndZero(),
-                            &non_interpolable_list);
+      std::make_unique<UnderlyingFilterListChecker>(interpolable_list));
+  return InterpolationValue(underlying.interpolable_value->CloneAndZero());
 }
 
 InterpolationValue CSSFilterListInterpolationType::MaybeConvertInitial(
@@ -156,8 +152,7 @@
     ConversionCheckers&) const {
   auto* identifier_value = DynamicTo<CSSIdentifierValue>(value);
   if (identifier_value && identifier_value->GetValueID() == CSSValueID::kNone)
-    return InterpolationValue(std::make_unique<InterpolableList>(0),
-                              NonInterpolableList::Create());
+    return InterpolationValue(std::make_unique<InterpolableList>(0));
 
   if (!value.IsBaseValueList())
     return nullptr;
@@ -165,19 +160,14 @@
   const auto& list = To<CSSValueList>(value);
   wtf_size_t length = list.length();
   auto interpolable_list = std::make_unique<InterpolableList>(length);
-  Vector<scoped_refptr<const NonInterpolableValue>> non_interpolable_values(
-      length);
   for (wtf_size_t i = 0; i < length; i++) {
-    InterpolationValue item_result =
-        filter_interpolation_functions::MaybeConvertCSSFilter(list.Item(i));
-    if (!item_result)
+    std::unique_ptr<InterpolableFilter> result =
+        InterpolableFilter::MaybeConvertCSSValue(list.Item(i));
+    if (!result)
       return nullptr;
-    interpolable_list->Set(i, std::move(item_result.interpolable_value));
-    non_interpolable_values[i] = std::move(item_result.non_interpolable_value);
+    interpolable_list->Set(i, std::move(result));
   }
-  return InterpolationValue(
-      std::move(interpolable_list),
-      NonInterpolableList::Create(std::move(non_interpolable_values)));
+  return InterpolationValue(std::move(interpolable_list));
 }
 
 InterpolationValue
@@ -190,38 +180,35 @@
 PairwiseInterpolationValue CSSFilterListInterpolationType::MaybeMergeSingles(
     InterpolationValue&& start,
     InterpolationValue&& end) const {
-  const NonInterpolableList& start_non_interpolable_list =
-      ToNonInterpolableList(*start.non_interpolable_value);
-  const NonInterpolableList& end_non_interpolable_list =
-      ToNonInterpolableList(*end.non_interpolable_value);
-  wtf_size_t start_length = start_non_interpolable_list.length();
-  wtf_size_t end_length = end_non_interpolable_list.length();
+  InterpolableList& start_interpolable_list =
+      ToInterpolableList(*start.interpolable_value);
+  InterpolableList& end_interpolable_list =
+      ToInterpolableList(*end.interpolable_value);
+  wtf_size_t start_length = start_interpolable_list.length();
+  wtf_size_t end_length = end_interpolable_list.length();
 
   for (wtf_size_t i = 0; i < start_length && i < end_length; i++) {
-    if (!filter_interpolation_functions::FiltersAreCompatible(
-            *start_non_interpolable_list.Get(i),
-            *end_non_interpolable_list.Get(i)))
+    if (To<InterpolableFilter>(start_interpolable_list.Get(i))->GetType() !=
+        To<InterpolableFilter>(end_interpolable_list.Get(i))->GetType())
       return nullptr;
   }
 
   if (start_length == end_length) {
     return PairwiseInterpolationValue(std::move(start.interpolable_value),
-                                      std::move(end.interpolable_value),
-                                      std::move(start.non_interpolable_value));
+                                      std::move(end.interpolable_value));
   }
 
   // Extend the shorter InterpolableList with neutral values that are compatible
   // with corresponding filters in the longer list.
   InterpolationValue& shorter = start_length < end_length ? start : end;
-  InterpolationValue& longer = start_length < end_length ? end : start;
-  wtf_size_t shorter_length =
-      ToNonInterpolableList(*shorter.non_interpolable_value).length();
-  wtf_size_t longer_length =
-      ToNonInterpolableList(*longer.non_interpolable_value).length();
-  InterpolableList& shorter_interpolable_list =
-      ToInterpolableList(*shorter.interpolable_value);
-  const NonInterpolableList& longer_non_interpolable_list =
-      ToNonInterpolableList(*longer.non_interpolable_value);
+  wtf_size_t shorter_length = std::min(start_length, end_length);
+  wtf_size_t longer_length = std::max(start_length, end_length);
+  InterpolableList& shorter_interpolable_list = start_length < end_length
+                                                    ? start_interpolable_list
+                                                    : end_interpolable_list;
+  const InterpolableList& longer_interpolable_list =
+      start_length < end_length ? end_interpolable_list
+                                : start_interpolable_list;
   auto extended_interpolable_list =
       std::make_unique<InterpolableList>(longer_length);
   for (wtf_size_t i = 0; i < longer_length; i++) {
@@ -230,14 +217,14 @@
           i, std::move(shorter_interpolable_list.GetMutable(i)));
     else
       extended_interpolable_list->Set(
-          i, filter_interpolation_functions::CreateNoneValue(
-                 *longer_non_interpolable_list.Get(i)));
+          i, InterpolableFilter::CreateInitialValue(
+                 To<InterpolableFilter>(longer_interpolable_list.Get(i))
+                     ->GetType()));
   }
   shorter.interpolable_value = std::move(extended_interpolable_list);
 
   return PairwiseInterpolationValue(std::move(start.interpolable_value),
-                                    std::move(end.interpolable_value),
-                                    std::move(longer.non_interpolable_value));
+                                    std::move(end.interpolable_value));
 }
 
 void CSSFilterListInterpolationType::Composite(
@@ -245,44 +232,40 @@
     double underlying_fraction,
     const InterpolationValue& value,
     double interpolation_fraction) const {
-  const NonInterpolableList& underlying_non_interpolable_list =
-      ToNonInterpolableList(
-          *underlying_value_owner.Value().non_interpolable_value);
-  const NonInterpolableList& non_interpolable_list =
-      ToNonInterpolableList(*value.non_interpolable_value);
-  wtf_size_t underlying_length = underlying_non_interpolable_list.length();
-  wtf_size_t length = non_interpolable_list.length();
+  // TODO(crbug.com/1005828): The below behavior is not correct for addition of
+  // filter values. Additive composition is defined as list concatenation in the
+  // spec: https://drafts.fxtf.org/filter-effects-1/#addition
+  InterpolableList& underlying_list =
+      ToInterpolableList(*underlying_value_owner.Value().interpolable_value);
+  const InterpolableList& interpolable_list =
+      ToInterpolableList(*value.interpolable_value);
+  wtf_size_t underlying_length = underlying_list.length();
+  wtf_size_t length = interpolable_list.length();
 
   for (wtf_size_t i = 0; i < underlying_length && i < length; i++) {
-    if (!filter_interpolation_functions::FiltersAreCompatible(
-            *underlying_non_interpolable_list.Get(i),
-            *non_interpolable_list.Get(i))) {
+    if (To<InterpolableFilter>(interpolable_list.Get(i))->GetType() !=
+        To<InterpolableFilter>(underlying_list.Get(i))->GetType()) {
       underlying_value_owner.Set(*this, value);
       return;
     }
   }
 
-  InterpolableList& underlying_interpolable_list = ToInterpolableList(
-      *underlying_value_owner.MutableValue().interpolable_value);
-  const InterpolableList& interpolable_list =
-      ToInterpolableList(*value.interpolable_value);
-  DCHECK_EQ(underlying_length, underlying_interpolable_list.length());
-  DCHECK_EQ(length, interpolable_list.length());
-
-  for (wtf_size_t i = 0; i < length && i < underlying_length; i++)
-    underlying_interpolable_list.GetMutable(i)->ScaleAndAdd(
-        underlying_fraction, *interpolable_list.Get(i));
+  for (wtf_size_t i = 0; i < length && i < underlying_length; i++) {
+    underlying_list.GetMutable(i)->ScaleAndAdd(underlying_fraction,
+                                               *interpolable_list.Get(i));
+  }
 
   if (length <= underlying_length)
     return;
 
   auto extended_interpolable_list = std::make_unique<InterpolableList>(length);
   for (wtf_size_t i = 0; i < length; i++) {
-    if (i < underlying_length)
-      extended_interpolable_list->Set(
-          i, std::move(underlying_interpolable_list.GetMutable(i)));
-    else
+    if (i < underlying_length) {
+      extended_interpolable_list->Set(i,
+                                      std::move(underlying_list.GetMutable(i)));
+    } else {
       extended_interpolable_list->Set(i, interpolable_list.Get(i)->Clone());
+    }
   }
   underlying_value_owner.MutableValue().interpolable_value =
       std::move(extended_interpolable_list);
@@ -296,17 +279,14 @@
     StyleResolverState& state) const {
   const InterpolableList& interpolable_list =
       ToInterpolableList(interpolable_value);
-  const NonInterpolableList& non_interpolable_list =
-      ToNonInterpolableList(*non_interpolable_value);
   wtf_size_t length = interpolable_list.length();
-  DCHECK_EQ(length, non_interpolable_list.length());
 
   FilterOperations filter_operations;
   filter_operations.Operations().ReserveCapacity(length);
   for (wtf_size_t i = 0; i < length; i++) {
     filter_operations.Operations().push_back(
-        filter_interpolation_functions::CreateFilter(
-            *interpolable_list.Get(i), *non_interpolable_list.Get(i), state));
+        To<InterpolableFilter>(interpolable_list.Get(i))
+            ->CreateFilterOperation(state));
   }
   SetFilterList(CssProperty(), *state.Style(), std::move(filter_operations));
 }
diff --git a/third_party/blink/renderer/core/animation/filter_interpolation_functions.cc b/third_party/blink/renderer/core/animation/filter_interpolation_functions.cc
deleted file mode 100644
index 6355d93..0000000
--- a/third_party/blink/renderer/core/animation/filter_interpolation_functions.cc
+++ /dev/null
@@ -1,261 +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 "third_party/blink/renderer/core/animation/filter_interpolation_functions.h"
-
-#include <memory>
-#include "third_party/blink/renderer/core/animation/interpolable_length.h"
-#include "third_party/blink/renderer/core/animation/interpolable_shadow.h"
-#include "third_party/blink/renderer/core/css/css_function_value.h"
-#include "third_party/blink/renderer/core/css/css_primitive_value.h"
-#include "third_party/blink/renderer/core/css/resolver/filter_operation_resolver.h"
-#include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
-#include "third_party/blink/renderer/core/style/filter_operations.h"
-#include "third_party/blink/renderer/core/style/shadow_data.h"
-
-namespace blink {
-
-class FilterNonInterpolableValue : public NonInterpolableValue {
- public:
-  static scoped_refptr<FilterNonInterpolableValue> Create(
-      FilterOperation::OperationType type,
-      scoped_refptr<const NonInterpolableValue> type_non_interpolable_value) {
-    return base::AdoptRef(new FilterNonInterpolableValue(
-        type, std::move(type_non_interpolable_value)));
-  }
-
-  FilterOperation::OperationType GetOperationType() const { return type_; }
-  const NonInterpolableValue* TypeNonInterpolableValue() const {
-    return type_non_interpolable_value_.get();
-  }
-
-  DECLARE_NON_INTERPOLABLE_VALUE_TYPE();
-
- private:
-  FilterNonInterpolableValue(
-      FilterOperation::OperationType type,
-      scoped_refptr<const NonInterpolableValue> type_non_interpolable_value)
-      : type_(type),
-        type_non_interpolable_value_(std::move(type_non_interpolable_value)) {}
-
-  const FilterOperation::OperationType type_;
-  scoped_refptr<const NonInterpolableValue> type_non_interpolable_value_;
-};
-
-DEFINE_NON_INTERPOLABLE_VALUE_TYPE(FilterNonInterpolableValue);
-DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(FilterNonInterpolableValue);
-
-namespace {
-
-double ClampParameter(double value, FilterOperation::OperationType type) {
-  switch (type) {
-    case FilterOperation::BRIGHTNESS:
-    case FilterOperation::CONTRAST:
-    case FilterOperation::SATURATE:
-      return clampTo<double>(value, 0);
-
-    case FilterOperation::GRAYSCALE:
-    case FilterOperation::INVERT:
-    case FilterOperation::OPACITY:
-    case FilterOperation::SEPIA:
-      return clampTo<double>(value, 0, 1);
-
-    case FilterOperation::HUE_ROTATE:
-      return value;
-
-    default:
-      NOTREACHED();
-      return 0;
-  }
-}
-
-}  // namespace
-
-InterpolationValue filter_interpolation_functions::MaybeConvertCSSFilter(
-    const CSSValue& value) {
-  if (value.IsURIValue())
-    return nullptr;
-
-  const auto& filter = To<CSSFunctionValue>(value);
-  DCHECK_LE(filter.length(), 1u);
-  FilterOperation::OperationType type =
-      FilterOperationResolver::FilterOperationForType(filter.FunctionType());
-  InterpolationValue result = nullptr;
-
-  switch (type) {
-    case FilterOperation::BRIGHTNESS:
-    case FilterOperation::CONTRAST:
-    case FilterOperation::GRAYSCALE:
-    case FilterOperation::INVERT:
-    case FilterOperation::OPACITY:
-    case FilterOperation::SATURATE:
-    case FilterOperation::SEPIA:
-    case FilterOperation::HUE_ROTATE:
-      result.interpolable_value = std::make_unique<InterpolableNumber>(
-          FilterOperationResolver::ResolveNumericArgumentForFunction(filter));
-      break;
-
-    case FilterOperation::BLUR: {
-      if (filter.length() == 0) {
-        result.interpolable_value = InterpolableLength::CreateNeutral();
-      } else {
-        result = InterpolationValue(
-            InterpolableLength::MaybeConvertCSSValue(filter.Item(0)));
-      }
-      break;
-    }
-
-    case FilterOperation::DROP_SHADOW:
-      result.interpolable_value =
-          InterpolableShadow::MaybeConvertCSSValue(filter.Item(0));
-      break;
-
-    default:
-      NOTREACHED();
-      return nullptr;
-  }
-
-  if (!result)
-    return nullptr;
-
-  result.non_interpolable_value = FilterNonInterpolableValue::Create(
-      type, std::move(result.non_interpolable_value));
-  return result;
-}
-
-InterpolationValue filter_interpolation_functions::MaybeConvertFilter(
-    const FilterOperation& filter,
-    double zoom) {
-  InterpolationValue result = nullptr;
-
-  switch (filter.GetType()) {
-    case FilterOperation::GRAYSCALE:
-    case FilterOperation::HUE_ROTATE:
-    case FilterOperation::SATURATE:
-    case FilterOperation::SEPIA:
-      result.interpolable_value = std::make_unique<InterpolableNumber>(
-          To<BasicColorMatrixFilterOperation>(filter).Amount());
-      break;
-
-    case FilterOperation::BRIGHTNESS:
-    case FilterOperation::CONTRAST:
-    case FilterOperation::INVERT:
-    case FilterOperation::OPACITY:
-      result.interpolable_value = std::make_unique<InterpolableNumber>(
-          To<BasicComponentTransferFilterOperation>(filter).Amount());
-      break;
-
-    case FilterOperation::BLUR:
-      result = InterpolationValue(InterpolableLength::MaybeConvertLength(
-          To<BlurFilterOperation>(filter).StdDeviation(), zoom));
-      break;
-
-    case FilterOperation::DROP_SHADOW:
-      result.interpolable_value = InterpolableShadow::Create(
-          To<DropShadowFilterOperation>(filter).Shadow(), zoom);
-      break;
-
-    case FilterOperation::REFERENCE:
-      return nullptr;
-
-    default:
-      NOTREACHED();
-      return nullptr;
-  }
-
-  if (!result)
-    return nullptr;
-
-  result.non_interpolable_value = FilterNonInterpolableValue::Create(
-      filter.GetType(), std::move(result.non_interpolable_value));
-  return result;
-}
-
-std::unique_ptr<InterpolableValue>
-filter_interpolation_functions::CreateNoneValue(
-    const NonInterpolableValue& untyped_value) {
-  switch (ToFilterNonInterpolableValue(untyped_value).GetOperationType()) {
-    case FilterOperation::GRAYSCALE:
-    case FilterOperation::INVERT:
-    case FilterOperation::SEPIA:
-    case FilterOperation::HUE_ROTATE:
-      return std::make_unique<InterpolableNumber>(0);
-
-    case FilterOperation::BRIGHTNESS:
-    case FilterOperation::CONTRAST:
-    case FilterOperation::OPACITY:
-    case FilterOperation::SATURATE:
-      return std::make_unique<InterpolableNumber>(1);
-
-    case FilterOperation::BLUR:
-      return InterpolableLength::CreateNeutral();
-
-    case FilterOperation::DROP_SHADOW:
-      return InterpolableShadow::CreateNeutral();
-
-    default:
-      NOTREACHED();
-      return nullptr;
-  }
-}
-
-bool filter_interpolation_functions::FiltersAreCompatible(
-    const NonInterpolableValue& a,
-    const NonInterpolableValue& b) {
-  return ToFilterNonInterpolableValue(a).GetOperationType() ==
-         ToFilterNonInterpolableValue(b).GetOperationType();
-}
-
-FilterOperation* filter_interpolation_functions::CreateFilter(
-    const InterpolableValue& interpolable_value,
-    const NonInterpolableValue& untyped_non_interpolable_value,
-    const StyleResolverState& state) {
-  const FilterNonInterpolableValue& non_interpolable_value =
-      ToFilterNonInterpolableValue(untyped_non_interpolable_value);
-  FilterOperation::OperationType type =
-      non_interpolable_value.GetOperationType();
-
-  switch (type) {
-    case FilterOperation::GRAYSCALE:
-    case FilterOperation::HUE_ROTATE:
-    case FilterOperation::SATURATE:
-    case FilterOperation::SEPIA: {
-      double value = ClampParameter(
-          ToInterpolableNumber(interpolable_value).Value(), type);
-      return MakeGarbageCollected<BasicColorMatrixFilterOperation>(value, type);
-    }
-
-    case FilterOperation::BRIGHTNESS:
-    case FilterOperation::CONTRAST:
-    case FilterOperation::INVERT:
-    case FilterOperation::OPACITY: {
-      double value = ClampParameter(
-          ToInterpolableNumber(interpolable_value).Value(), type);
-      return MakeGarbageCollected<BasicComponentTransferFilterOperation>(value,
-                                                                         type);
-    }
-
-    case FilterOperation::BLUR: {
-      Length std_deviation =
-          To<InterpolableLength>(interpolable_value)
-              .CreateLength(state.CssToLengthConversionData(),
-                            kValueRangeNonNegative);
-      return MakeGarbageCollected<BlurFilterOperation>(std_deviation);
-    }
-
-    case FilterOperation::DROP_SHADOW: {
-      ShadowData shadow_data =
-          To<InterpolableShadow>(interpolable_value).CreateShadowData(state);
-      if (shadow_data.GetColor().IsCurrentColor())
-        shadow_data.OverrideColor(Color::kBlack);
-      return DropShadowFilterOperation::Create(shadow_data);
-    }
-
-    default:
-      NOTREACHED();
-      return nullptr;
-  }
-}
-
-}  // namespace blink
diff --git a/third_party/blink/renderer/core/animation/filter_interpolation_functions.h b/third_party/blink/renderer/core/animation/filter_interpolation_functions.h
deleted file mode 100644
index 799a8bd..0000000
--- a/third_party/blink/renderer/core/animation/filter_interpolation_functions.h
+++ /dev/null
@@ -1,33 +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 THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_FILTER_INTERPOLATION_FUNCTIONS_H_
-#define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_FILTER_INTERPOLATION_FUNCTIONS_H_
-
-#include <memory>
-#include "third_party/blink/renderer/core/animation/interpolation_value.h"
-#include "third_party/blink/renderer/platform/heap/handle.h"
-
-namespace blink {
-
-class FilterOperation;
-class CSSValue;
-class StyleResolverState;
-
-namespace filter_interpolation_functions {
-
-InterpolationValue MaybeConvertCSSFilter(const CSSValue&);
-InterpolationValue MaybeConvertFilter(const FilterOperation&, double zoom);
-std::unique_ptr<InterpolableValue> CreateNoneValue(const NonInterpolableValue&);
-bool FiltersAreCompatible(const NonInterpolableValue&,
-                          const NonInterpolableValue&);
-FilterOperation* CreateFilter(const InterpolableValue&,
-                              const NonInterpolableValue&,
-                              const StyleResolverState&);
-
-}  // namespace filter_interpolation_functions
-
-}  // namespace blink
-
-#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_FILTER_INTERPOLATION_FUNCTIONS_H_
diff --git a/third_party/blink/renderer/core/animation/interpolable_filter.cc b/third_party/blink/renderer/core/animation/interpolable_filter.cc
new file mode 100644
index 0000000..2b23c11
--- /dev/null
+++ b/third_party/blink/renderer/core/animation/interpolable_filter.cc
@@ -0,0 +1,225 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "third_party/blink/renderer/core/animation/interpolable_filter.h"
+#include "third_party/blink/renderer/core/animation/interpolable_length.h"
+#include "third_party/blink/renderer/core/animation/interpolable_shadow.h"
+#include "third_party/blink/renderer/core/css/css_function_value.h"
+#include "third_party/blink/renderer/core/css/css_identifier_value.h"
+#include "third_party/blink/renderer/core/css/css_shadow_value.h"
+#include "third_party/blink/renderer/core/css/css_value.h"
+#include "third_party/blink/renderer/core/css/resolver/filter_operation_resolver.h"
+#include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
+
+namespace blink {
+namespace {
+double ClampParameter(double value, FilterOperation::OperationType type) {
+  switch (type) {
+    case FilterOperation::BRIGHTNESS:
+    case FilterOperation::CONTRAST:
+    case FilterOperation::SATURATE:
+      return clampTo<double>(value, 0);
+
+    case FilterOperation::GRAYSCALE:
+    case FilterOperation::INVERT:
+    case FilterOperation::OPACITY:
+    case FilterOperation::SEPIA:
+      return clampTo<double>(value, 0, 1);
+
+    case FilterOperation::HUE_ROTATE:
+      return value;
+
+    default:
+      NOTREACHED();
+      return 0;
+  }
+}
+}  // namespace
+
+// static
+std::unique_ptr<InterpolableFilter> InterpolableFilter::MaybeCreate(
+    const FilterOperation& filter,
+    double zoom) {
+  std::unique_ptr<InterpolableValue> value = nullptr;
+  FilterOperation::OperationType type = filter.GetType();
+  switch (type) {
+    case FilterOperation::GRAYSCALE:
+    case FilterOperation::HUE_ROTATE:
+    case FilterOperation::SATURATE:
+    case FilterOperation::SEPIA:
+      value = std::make_unique<InterpolableNumber>(
+          To<BasicColorMatrixFilterOperation>(filter).Amount());
+      break;
+
+    case FilterOperation::BRIGHTNESS:
+    case FilterOperation::CONTRAST:
+    case FilterOperation::INVERT:
+    case FilterOperation::OPACITY:
+      value = std::make_unique<InterpolableNumber>(
+          To<BasicComponentTransferFilterOperation>(filter).Amount());
+      break;
+
+    case FilterOperation::BLUR:
+      value = InterpolableLength::MaybeConvertLength(
+          To<BlurFilterOperation>(filter).StdDeviation(), zoom);
+      break;
+
+    case FilterOperation::DROP_SHADOW:
+      value = InterpolableShadow::Create(
+          To<DropShadowFilterOperation>(filter).Shadow(), zoom);
+      break;
+
+    case FilterOperation::REFERENCE:
+      return nullptr;
+
+    default:
+      NOTREACHED();
+      return nullptr;
+  }
+
+  if (!value)
+    return nullptr;
+  return std::make_unique<InterpolableFilter>(std::move(value), type);
+}
+
+// static
+std::unique_ptr<InterpolableFilter> InterpolableFilter::MaybeConvertCSSValue(
+    const CSSValue& css_value) {
+  if (css_value.IsURIValue())
+    return nullptr;
+
+  const auto& filter = To<CSSFunctionValue>(css_value);
+  DCHECK_LE(filter.length(), 1u);
+
+  std::unique_ptr<InterpolableValue> value = nullptr;
+  FilterOperation::OperationType type =
+      FilterOperationResolver::FilterOperationForType(filter.FunctionType());
+  switch (type) {
+    case FilterOperation::BRIGHTNESS:
+    case FilterOperation::CONTRAST:
+    case FilterOperation::GRAYSCALE:
+    case FilterOperation::INVERT:
+    case FilterOperation::OPACITY:
+    case FilterOperation::SATURATE:
+    case FilterOperation::SEPIA:
+    case FilterOperation::HUE_ROTATE:
+      value = std::make_unique<InterpolableNumber>(
+          FilterOperationResolver::ResolveNumericArgumentForFunction(filter));
+      break;
+
+    case FilterOperation::BLUR:
+      value = filter.length() > 0
+                  ? InterpolableLength::MaybeConvertCSSValue(filter.Item(0))
+                  : InterpolableLength::CreateNeutral();
+      break;
+
+    case FilterOperation::DROP_SHADOW:
+      value = InterpolableShadow::MaybeConvertCSSValue(filter.Item(0));
+      break;
+
+    default:
+      NOTREACHED();
+      return nullptr;
+  }
+
+  if (!value)
+    return nullptr;
+  return std::make_unique<InterpolableFilter>(std::move(value), type);
+}
+
+// static
+std::unique_ptr<InterpolableFilter> InterpolableFilter::CreateInitialValue(
+    FilterOperation::OperationType type) {
+  // See https://drafts.fxtf.org/filter-effects-1/#filter-functions for the
+  // mapping of OperationType to initial value.
+  std::unique_ptr<InterpolableValue> value = nullptr;
+  switch (type) {
+    case FilterOperation::GRAYSCALE:
+    case FilterOperation::INVERT:
+    case FilterOperation::SEPIA:
+    case FilterOperation::HUE_ROTATE:
+      value = std::make_unique<InterpolableNumber>(0);
+      break;
+
+    case FilterOperation::BRIGHTNESS:
+    case FilterOperation::CONTRAST:
+    case FilterOperation::OPACITY:
+    case FilterOperation::SATURATE:
+      value = std::make_unique<InterpolableNumber>(1);
+      break;
+
+    case FilterOperation::BLUR:
+      value = InterpolableLength::CreateNeutral();
+      break;
+
+    case FilterOperation::DROP_SHADOW:
+      value = InterpolableShadow::CreateNeutral();
+      break;
+
+    default:
+      NOTREACHED();
+      return nullptr;
+  }
+
+  return std::make_unique<InterpolableFilter>(std::move(value), type);
+}
+
+FilterOperation* InterpolableFilter::CreateFilterOperation(
+    const StyleResolverState& state) const {
+  switch (type_) {
+    case FilterOperation::GRAYSCALE:
+    case FilterOperation::HUE_ROTATE:
+    case FilterOperation::SATURATE:
+    case FilterOperation::SEPIA: {
+      double value =
+          ClampParameter(ToInterpolableNumber(*value_).Value(), type_);
+      return MakeGarbageCollected<BasicColorMatrixFilterOperation>(value,
+                                                                   type_);
+    }
+
+    case FilterOperation::BRIGHTNESS:
+    case FilterOperation::CONTRAST:
+    case FilterOperation::INVERT:
+    case FilterOperation::OPACITY: {
+      double value =
+          ClampParameter(ToInterpolableNumber(*value_).Value(), type_);
+      return MakeGarbageCollected<BasicComponentTransferFilterOperation>(value,
+                                                                         type_);
+    }
+
+    case FilterOperation::BLUR: {
+      Length std_deviation = To<InterpolableLength>(*value_).CreateLength(
+          state.CssToLengthConversionData(), kValueRangeNonNegative);
+      return MakeGarbageCollected<BlurFilterOperation>(std_deviation);
+    }
+
+    case FilterOperation::DROP_SHADOW: {
+      ShadowData shadow_data =
+          To<InterpolableShadow>(*value_).CreateShadowData(state);
+      if (shadow_data.GetColor().IsCurrentColor())
+        shadow_data.OverrideColor(Color::kBlack);
+      return DropShadowFilterOperation::Create(shadow_data);
+    }
+
+    default:
+      NOTREACHED();
+      return nullptr;
+  }
+}
+
+void InterpolableFilter::AssertCanInterpolateWith(
+    const InterpolableValue& other) const {
+  DCHECK(other.IsFilter());
+  DCHECK_EQ(type_, To<InterpolableFilter>(other).type_);
+}
+
+void InterpolableFilter::Interpolate(const InterpolableValue& to,
+                                     const double progress,
+                                     InterpolableValue& result) const {
+  const InterpolableFilter& filter_to = To<InterpolableFilter>(to);
+  InterpolableFilter& filter_result = To<InterpolableFilter>(result);
+  value_->Interpolate(*filter_to.value_, progress, *filter_result.value_);
+}
+
+}  // namespace blink
diff --git a/third_party/blink/renderer/core/animation/interpolable_filter.h b/third_party/blink/renderer/core/animation/interpolable_filter.h
new file mode 100644
index 0000000..a3f268f8
--- /dev/null
+++ b/third_party/blink/renderer/core/animation/interpolable_filter.h
@@ -0,0 +1,82 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_INTERPOLABLE_FILTER_H_
+#define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_INTERPOLABLE_FILTER_H_
+
+#include <memory>
+#include "third_party/blink/renderer/core/animation/interpolable_value.h"
+#include "third_party/blink/renderer/core/style/filter_operation.h"
+
+namespace blink {
+
+class CSSValue;
+class StyleResolverState;
+
+// Represents a blink::FilterOperation, converted into a form that can be
+// interpolated from/to.
+class CORE_EXPORT InterpolableFilter final : public InterpolableValue {
+ public:
+  InterpolableFilter(std::unique_ptr<InterpolableValue> value,
+                     FilterOperation::OperationType type)
+      : value_(std::move(value)), type_(type) {
+    DCHECK(value_);
+  }
+
+  static std::unique_ptr<InterpolableFilter> MaybeCreate(const FilterOperation&,
+                                                         double zoom);
+  static std::unique_ptr<InterpolableFilter> MaybeConvertCSSValue(
+      const CSSValue&);
+
+  // Create an InterpolableFilter representing the 'initial value for
+  // interpolation' for the given OperationType.
+  static std::unique_ptr<InterpolableFilter> CreateInitialValue(
+      FilterOperation::OperationType);
+
+  FilterOperation::OperationType GetType() const { return type_; }
+
+  // Convert this InterpolableFilter back into a FilterOperation class, usually
+  // to be applied to the style after interpolating |this|.
+  FilterOperation* CreateFilterOperation(const StyleResolverState&) const;
+
+  // InterpolableValue implementation:
+  void Interpolate(const InterpolableValue& to,
+                   const double progress,
+                   InterpolableValue& result) const final;
+  bool IsFilter() const final { return true; }
+  bool Equals(const InterpolableValue& other) const final {
+    NOTREACHED();
+    return false;
+  }
+  void Scale(double scale) final { NOTREACHED(); }
+  void ScaleAndAdd(double scale, const InterpolableValue& other) final {
+    value_->ScaleAndAdd(scale, *To<InterpolableFilter>(other).value_);
+  }
+  void AssertCanInterpolateWith(const InterpolableValue& other) const final;
+
+ private:
+  InterpolableFilter* RawClone() const final {
+    return new InterpolableFilter(value_->Clone(), type_);
+  }
+  InterpolableFilter* RawCloneAndZero() const final {
+    return new InterpolableFilter(value_->CloneAndZero(), type_);
+  }
+
+  // Stores the interpolable data for the filter. The form varies depending on
+  // the |type_|; see the implementation file for details of the mapping.
+  std::unique_ptr<InterpolableValue> value_;
+
+  FilterOperation::OperationType type_;
+};
+
+template <>
+struct DowncastTraits<InterpolableFilter> {
+  static bool AllowFrom(const InterpolableValue& interpolable_value) {
+    return interpolable_value.IsFilter();
+  }
+};
+
+}  // namespace blink
+
+#endif  // THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_INTERPOLABLE_FILTER_H_
diff --git a/third_party/blink/renderer/core/animation/interpolable_value.h b/third_party/blink/renderer/core/animation/interpolable_value.h
index 65915fa..2353b3a 100644
--- a/third_party/blink/renderer/core/animation/interpolable_value.h
+++ b/third_party/blink/renderer/core/animation/interpolable_value.h
@@ -39,6 +39,7 @@
   virtual bool IsList() const { return false; }
   virtual bool IsLength() const { return false; }
   virtual bool IsShadow() const { return false; }
+  virtual bool IsFilter() const { return false; }
 
   // TODO(alancutter): Remove Equals().
   virtual bool Equals(const InterpolableValue&) const = 0;
diff --git a/third_party/blink/renderer/core/animation_frame/worker_animation_frame_provider.cc b/third_party/blink/renderer/core/animation_frame/worker_animation_frame_provider.cc
index a5df271..6ddf2866 100644
--- a/third_party/blink/renderer/core/animation_frame/worker_animation_frame_provider.cc
+++ b/third_party/blink/renderer/core/animation_frame/worker_animation_frame_provider.cc
@@ -6,6 +6,7 @@
 
 #include "third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h"
 #include "third_party/blink/renderer/core/timing/worker_global_scope_performance.h"
+#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/wtf/cross_thread_functional.h"
 
 namespace blink {
@@ -35,27 +36,23 @@
   callback_collection_.CancelFrameCallback(id);
 }
 
-void WorkerAnimationFrameProvider::BeginFrame() {
-  // TODO(fserb): Remove this once the Mojo changes for scheduling are in.
-  context_->GetTaskRunner(TaskType::kWorkerAnimation)
-      ->PostTask(
-          FROM_HERE,
-          WTF::Bind(
-              [](base::WeakPtr<WorkerAnimationFrameProvider> provider) {
-                ExecutionContext* context = provider->context_;
-                Performance* performance =
-                    WorkerGlobalScopePerformance::performance(
-                        *To<WorkerGlobalScope>(context));
-                double time = performance->now();
+void WorkerAnimationFrameProvider::BeginFrame(
+    const base::TimeTicks& frame_time) {
+  TRACE_EVENT0("blink", "WorkerAnimationFrameProvider::BeginFrame");
 
-                provider->callback_collection_.ExecuteFrameCallbacks(time,
-                                                                     time);
+  double time = (frame_time - base::TimeTicks()).InMillisecondsF();
 
-                for (auto& offscreen_canvas : provider->offscreen_canvases_) {
-                  offscreen_canvas->PushFrameIfNeeded();
-                }
-              },
-              weak_factory_.GetWeakPtr()));
+  Microtask::EnqueueMicrotask(WTF::Bind(
+      [](base::WeakPtr<WorkerAnimationFrameProvider> provider, double time) {
+        TRACE_EVENT0("blink",
+                     "WorkerAnimationFrameProvider::RequestAnimationFrame");
+        provider->callback_collection_.ExecuteFrameCallbacks(time, time);
+
+        for (auto& offscreen_canvas : provider->offscreen_canvases_) {
+          offscreen_canvas->PushFrameIfNeeded();
+        }
+      },
+      weak_factory_.GetWeakPtr(), time));
 }
 
 void WorkerAnimationFrameProvider::RegisterOffscreenCanvas(
diff --git a/third_party/blink/renderer/core/animation_frame/worker_animation_frame_provider.h b/third_party/blink/renderer/core/animation_frame/worker_animation_frame_provider.h
index e987e6b4..b398620 100644
--- a/third_party/blink/renderer/core/animation_frame/worker_animation_frame_provider.h
+++ b/third_party/blink/renderer/core/animation_frame/worker_animation_frame_provider.h
@@ -39,8 +39,7 @@
   void Trace(blink::Visitor* visitor);
 
   // BeginFrameProviderClient
-  void BeginFrame() override;
-  bool InBeginFrame() const;
+  void BeginFrame(const base::TimeTicks& frame_time) override;
 
   void RegisterOffscreenCanvas(OffscreenCanvas*);
   void DeregisterOffscreenCanvas(OffscreenCanvas*);
@@ -55,7 +54,6 @@
   // To avoid leaking OffscreenCanvas objects, the following vector must
   // not hold strong references.
   Vector<UntracedMember<OffscreenCanvas>> offscreen_canvases_;
-  bool in_begin_frame_;
 
   Member<ExecutionContext> context_;
 
diff --git a/third_party/blink/renderer/core/dom/element.cc b/third_party/blink/renderer/core/dom/element.cc
index 2fad6d0..0a5cdb1f2 100644
--- a/third_party/blink/renderer/core/dom/element.cc
+++ b/third_party/blink/renderer/core/dom/element.cc
@@ -116,6 +116,7 @@
 #include "third_party/blink/renderer/core/html/custom/v0_custom_element_registration_context.h"
 #include "third_party/blink/renderer/core/html/forms/html_form_controls_collection.h"
 #include "third_party/blink/renderer/core/html/forms/html_options_collection.h"
+#include "third_party/blink/renderer/core/html/html_body_element.h"
 #include "third_party/blink/renderer/core/html/html_collection.h"
 #include "third_party/blink/renderer/core/html/html_document.h"
 #include "third_party/blink/renderer/core/html/html_element.h"
@@ -2656,10 +2657,11 @@
     if (ElementAnimations* element_animations = data->GetElementAnimations())
       element_animations->CssAnimations().Cancel();
 
-    if (data->IntersectionObserverData()) {
+    if (was_in_document && data->IntersectionObserverData()) {
       data->IntersectionObserverData()->ComputeIntersectionsForTarget(
           IntersectionObservation::kExplicitRootObserversNeedUpdate |
-          IntersectionObservation::kImplicitRootObserversNeedUpdate);
+          IntersectionObservation::kImplicitRootObserversNeedUpdate |
+          IntersectionObservation::kIgnoreDelay);
       GetDocument().EnsureIntersectionObserverController().RemoveTrackedElement(
           *this);
     }
@@ -4429,6 +4431,7 @@
   }
 }
 
+// Step 4 of http://domparsing.spec.whatwg.org/#insertadjacenthtml()
 Node* Element::InsertAdjacent(const String& where,
                               Node* new_child,
                               ExceptionState& exception_state) {
@@ -4537,13 +4540,13 @@
 }
 
 // Step 1 of http://domparsing.spec.whatwg.org/#insertadjacenthtml()
-static Element* ContextElementForInsertion(const String& where,
-                                           Element* element,
-                                           ExceptionState& exception_state) {
+static Node* ContextNodeForInsertion(const String& where,
+                                     Element* element,
+                                     ExceptionState& exception_state) {
   if (DeprecatedEqualIgnoringCase(where, "beforeBegin") ||
       DeprecatedEqualIgnoringCase(where, "afterEnd")) {
-    Element* parent = element->parentElement();
-    if (!parent) {
+    Node* parent = element->parentNode();
+    if (!parent || IsA<Document>(parent)) {
       exception_state.ThrowDOMException(
           DOMExceptionCode::kNoModificationAllowedError,
           "The element has no parent.");
@@ -4578,11 +4581,22 @@
 void Element::insertAdjacentHTML(const String& where,
                                  const String& markup,
                                  ExceptionState& exception_state) {
-  Element* context_element =
-      ContextElementForInsertion(where, this, exception_state);
-  if (!context_element)
+  Node* context_node = ContextNodeForInsertion(where, this, exception_state);
+  if (!context_node)
     return;
 
+  // Step 2 of http://domparsing.spec.whatwg.org/#insertadjacenthtml()
+  Element* context_element;
+  if (!IsA<Element>(context_node) ||
+      (context_node->GetDocument().IsHTMLDocument() &&
+       IsA<HTMLHtmlElement>(context_node))) {
+    context_element =
+        MakeGarbageCollected<HTMLBodyElement>(context_node->GetDocument());
+  } else {
+    context_element = To<Element>(context_node);
+  }
+
+  // Step 3 of http://domparsing.spec.whatwg.org/#insertadjacenthtml()
   DocumentFragment* fragment = CreateFragmentForInnerOuterHTML(
       markup, context_element, kAllowScriptingContent, "insertAdjacentHTML",
       exception_state);
diff --git a/third_party/blink/renderer/core/dom/element.h b/third_party/blink/renderer/core/dom/element.h
index 16b8e929..4672a45 100644
--- a/third_party/blink/renderer/core/dom/element.h
+++ b/third_party/blink/renderer/core/dom/element.h
@@ -995,6 +995,7 @@
 
   scoped_refptr<ComputedStyle> OriginalStyleForLayoutObject();
 
+  // Step 4 of http://domparsing.spec.whatwg.org/#insertadjacenthtml()
   Node* InsertAdjacent(const String& where, Node* new_child, ExceptionState&);
 
   virtual void ParserDidSetAttributes() {}
diff --git a/third_party/blink/renderer/core/dom/frame_request_callback_collection.cc b/third_party/blink/renderer/core/dom/frame_request_callback_collection.cc
index 7b1c989..094fef9 100644
--- a/third_party/blink/renderer/core/dom/frame_request_callback_collection.cc
+++ b/third_party/blink/renderer/core/dom/frame_request_callback_collection.cc
@@ -83,6 +83,8 @@
 void FrameRequestCallbackCollection::ExecuteFrameCallbacks(
     double high_res_now_ms,
     double high_res_now_ms_legacy) {
+  TRACE_EVENT0("blink",
+               "FrameRequestCallbackCollection::ExecuteFrameCallbacks");
   ExecuteCallbacksInternal(frame_callbacks_, "FireAnimationFrame",
                            "requestAnimationFrame", high_res_now_ms,
                            high_res_now_ms_legacy);
diff --git a/third_party/blink/renderer/core/fetch/DEPS b/third_party/blink/renderer/core/fetch/DEPS
index 15b3d08..5eb781fa 100644
--- a/third_party/blink/renderer/core/fetch/DEPS
+++ b/third_party/blink/renderer/core/fetch/DEPS
@@ -5,4 +5,5 @@
     "+mojo/public/cpp/system/data_pipe.h",
     "+mojo/public/cpp/system/simple_watcher.h",
     "+net/base/request_priority.h",
+    "+services/network/public/cpp/content_security_policy.h",
 ]
diff --git a/third_party/blink/renderer/core/fetch/fetch_response_data.cc b/third_party/blink/renderer/core/fetch/fetch_response_data.cc
index 53c95f8..69854eb 100644
--- a/third_party/blink/renderer/core/fetch/fetch_response_data.cc
+++ b/third_party/blink/renderer/core/fetch/fetch_response_data.cc
@@ -4,6 +4,9 @@
 
 #include "third_party/blink/renderer/core/fetch/fetch_response_data.h"
 
+#include "services/network/public/cpp/content_security_policy.h"
+#include "services/network/public/cpp/features.h"
+#include "services/network/public/mojom/content_security_policy.mojom-blink.h"
 #include "third_party/blink/renderer/core/fetch/fetch_header_list.h"
 #include "third_party/blink/renderer/core/typed_arrays/dom_array_buffer.h"
 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
@@ -12,6 +15,7 @@
 #include "third_party/blink/renderer/platform/loader/fetch/fetch_utils.h"
 #include "third_party/blink/renderer/platform/network/http_names.h"
 #include "third_party/blink/renderer/platform/wtf/std_lib_extras.h"
+#include "third_party/blink/renderer/platform/wtf/text/string_utf8_adaptor.h"
 
 using Type = network::mojom::FetchResponseType;
 using ResponseSource = network::mojom::FetchResponseSource;
@@ -253,6 +257,40 @@
       HeaderSetToVector(cors_exposed_header_names_);
   for (const auto& header : HeaderList()->List())
     response->headers.insert(header.first, header.second);
+
+  // Check if there's a Content-Security-Policy header and parse it if
+  // necessary.
+  if (base::FeatureList::IsEnabled(
+          network::features::kOutOfBlinkFrameAncestors)) {
+    String content_security_policy_header;
+    if (HeaderList()->Get("content-security-policy",
+                          content_security_policy_header)) {
+      network::ContentSecurityPolicy policy;
+      if (policy.Parse(StringUTF8Adaptor(content_security_policy_header)
+                           .AsStringPiece())) {
+        const network::mojom::CSPSourceListPtr& frame_ancestors_directive =
+            policy.content_security_policy_ptr()->frame_ancestors;
+        if (frame_ancestors_directive) {
+          // Convert network::mojom::ContentSecurityPolicy to
+          // network::mojom::blink::ContentSecurityPolicy.
+          auto blink_frame_ancestors =
+              network::mojom::blink::CSPSourceList::New();
+          for (auto& csp_source : frame_ancestors_directive->sources) {
+            blink_frame_ancestors->sources.push_back(
+                network::mojom::blink::CSPSource::New(
+                    String::FromUTF8(csp_source->scheme),
+                    String::FromUTF8(csp_source->host), csp_source->port,
+                    String::FromUTF8(csp_source->path),
+                    csp_source->is_host_wildcard, csp_source->is_port_wildcard,
+                    csp_source->allow_self));
+          }
+          response->content_security_policy =
+              network::mojom::blink::ContentSecurityPolicy::New(
+                  std::move(blink_frame_ancestors));
+        }
+      }
+    }
+  }
   return response;
 }
 
diff --git a/third_party/blink/renderer/core/fileapi/blob.cc b/third_party/blink/renderer/core/fileapi/blob.cc
index 0a1eeb2..09f21e5 100644
--- a/third_party/blink/renderer/core/fileapi/blob.cc
+++ b/third_party/blink/renderer/core/fileapi/blob.cc
@@ -259,6 +259,14 @@
   return instance;
 }
 
+bool Blob::IsMojoBlob() {
+  return true;
+}
+
+void Blob::CloneMojoBlob(mojo::PendingReceiver<mojom::blink::Blob> receiver) {
+  blob_data_handle_->CloneBlobRemote(std::move(receiver));
+}
+
 mojo::PendingRemote<mojom::blink::Blob> Blob::AsMojoBlob() {
   return blob_data_handle_->CloneBlobRemote();
 }
diff --git a/third_party/blink/renderer/core/fileapi/blob.h b/third_party/blink/renderer/core/fileapi/blob.h
index f481ceb..241ec41 100644
--- a/third_party/blink/renderer/core/fileapi/blob.h
+++ b/third_party/blink/renderer/core/fileapi/blob.h
@@ -118,7 +118,9 @@
 
   // URLRegistrable to support PublicURLs.
   URLRegistry& Registry() const final;
-  mojo::PendingRemote<mojom::blink::Blob> AsMojoBlob() final;
+  bool IsMojoBlob() final;
+  void CloneMojoBlob(mojo::PendingReceiver<mojom::blink::Blob>) final;
+  mojo::PendingRemote<mojom::blink::Blob> AsMojoBlob();
 
   // ImageBitmapSource implementation
   bool IsBlob() const override { return true; }
diff --git a/third_party/blink/renderer/core/fileapi/public_url_manager.cc b/third_party/blink/renderer/core/fileapi/public_url_manager.cc
index 13b2150..f717b64 100644
--- a/third_party/blink/renderer/core/fileapi/public_url_manager.cc
+++ b/third_party/blink/renderer/core/fileapi/public_url_manager.cc
@@ -112,16 +112,19 @@
   DCHECK(!url.IsEmpty());
   const String& url_string = url.GetString();
 
-  mojo::PendingRemote<mojom::blink::Blob> blob = registrable->AsMojoBlob();
-  if (blob) {
+  if (registrable->IsMojoBlob()) {
     // Measure how much jank the following synchronous IPC introduces.
     SCOPED_UMA_HISTOGRAM_TIMER("Storage.Blob.RegisterPublicURLTime");
     if (!url_store_) {
       BlobDataHandle::GetBlobRegistry()->URLStoreForOrigin(
           origin, url_store_.BindNewEndpointAndPassReceiver());
     }
-    url_store_->Register(std::move(blob), url);
+    mojo::PendingRemote<mojom::blink::Blob> blob_remote;
+    mojo::PendingReceiver<mojom::blink::Blob> blob_receiver =
+        blob_remote.InitWithNewPipeAndPassReceiver();
+    url_store_->Register(std::move(blob_remote), url);
     mojo_urls_.insert(url_string);
+    registrable->CloneMojoBlob(std::move(blob_receiver));
   } else {
     URLRegistry* registry = &registrable->Registry();
     registry->RegisterURL(origin, url, registrable);
diff --git a/third_party/blink/renderer/core/fileapi/public_url_manager_test.cc b/third_party/blink/renderer/core/fileapi/public_url_manager_test.cc
index fcc95bb..4947144 100644
--- a/third_party/blink/renderer/core/fileapi/public_url_manager_test.cc
+++ b/third_party/blink/renderer/core/fileapi/public_url_manager_test.cc
@@ -32,12 +32,13 @@
 
   URLRegistry& Registry() const override { return *registry_; }
 
-  mojo::PendingRemote<mojom::blink::Blob> AsMojoBlob() override {
+  bool IsMojoBlob() override { return bool{blob_}; }
+
+  void CloneMojoBlob(
+      mojo::PendingReceiver<mojom::blink::Blob> receiver) override {
     if (!blob_)
-      return mojo::NullRemote();
-    mojo::PendingRemote<mojom::blink::Blob> result;
-    blob_->Clone(result.InitWithNewPipeAndPassReceiver());
-    return result;
+      return;
+    blob_->Clone(std::move(receiver));
   }
 
  private:
diff --git a/third_party/blink/renderer/core/fileapi/url_registry.h b/third_party/blink/renderer/core/fileapi/url_registry.h
index e89d005..4a6db25e 100644
--- a/third_party/blink/renderer/core/fileapi/url_registry.h
+++ b/third_party/blink/renderer/core/fileapi/url_registry.h
@@ -46,9 +46,8 @@
  public:
   virtual ~URLRegistrable() = default;
   virtual URLRegistry& Registry() const = 0;
-  virtual mojo::PendingRemote<mojom::blink::Blob> AsMojoBlob() {
-    return mojo::NullRemote();
-  }
+  virtual bool IsMojoBlob() { return false; }
+  virtual void CloneMojoBlob(mojo::PendingReceiver<mojom::blink::Blob>) {}
 };
 
 class CORE_EXPORT URLRegistry {
diff --git a/third_party/blink/renderer/core/frame/deprecation.cc b/third_party/blink/renderer/core/frame/deprecation.cc
index 7803562..98fc6458 100644
--- a/third_party/blink/renderer/core/frame/deprecation.cc
+++ b/third_party/blink/renderer/core/frame/deprecation.cc
@@ -666,6 +666,12 @@
                             "elements other than textarea",
                             kM79, "5070237827334144")};
 
+    case WebFeature::kXRSupportsSession:
+      return {"XRSupportsSession", kM80,
+              ReplacedBy(
+                  "supportsSession()",
+                  "isSessionSupported() and check the resolved boolean value")};
+
     // Features that aren't deprecated don't have a deprecation message.
     default:
       return {"NotDeprecated", kUnknown, ""};
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
index b065c84..32456b7 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
+++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context.h
@@ -180,7 +180,7 @@
   }
 
   // OffscreenCanvas-specific methods
-  virtual void PushFrame() {}
+  virtual bool PushFrame() { return false; }
   virtual ImageBitmap* TransferToImageBitmap(ScriptState*) { return nullptr; }
 
   bool WouldTaintOrigin(CanvasImageSource*);
diff --git a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h
index 74282e90..a4f4175 100644
--- a/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h
+++ b/third_party/blink/renderer/core/html/canvas/canvas_rendering_context_host.h
@@ -47,7 +47,7 @@
   virtual void DidDraw() = 0;
 
   virtual void FinalizeFrame() = 0;
-  virtual void PushFrame(scoped_refptr<CanvasResource> frame,
+  virtual bool PushFrame(scoped_refptr<CanvasResource> frame,
                          const SkIRect& damage_rect) = 0;
   virtual bool OriginClean() const = 0;
   virtual void SetOriginTainted() = 0;
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
index 77c908e..d07a252 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.cc
@@ -1010,9 +1010,10 @@
   return frame_dispatcher_.get();
 }
 
-void HTMLCanvasElement::PushFrame(scoped_refptr<CanvasResource> image,
+bool HTMLCanvasElement::PushFrame(scoped_refptr<CanvasResource> image,
                                   const SkIRect& damage_rect) {
   NOTIMPLEMENTED();
+  return false;
 }
 
 bool HTMLCanvasElement::ShouldAccelerate(AccelerationCriteria criteria) const {
diff --git a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
index dcbd750..fc2dd311c 100644
--- a/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
+++ b/third_party/blink/renderer/core/html/canvas/html_canvas_element.h
@@ -189,7 +189,7 @@
 
   CanvasResourceDispatcher* GetOrCreateResourceDispatcher() override;
 
-  void PushFrame(scoped_refptr<CanvasResource> image,
+  bool PushFrame(scoped_refptr<CanvasResource> image,
                  const SkIRect& damage_rect) override;
 
   // ContextLifecycleObserver and PageVisibilityObserver implementation
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc b/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc
index 13180f9..ed942cd 100644
--- a/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc
+++ b/third_party/blink/renderer/core/intersection_observer/intersection_observation.cc
@@ -70,7 +70,11 @@
     ElementIntersectionObserverData* observer_data =
         target_->IntersectionObserverData();
     observer_data->RemoveObservation(*Observer());
-    if (target_->isConnected() &&
+    // We track connected elements that are either the root of an explicit root
+    // observer, or the target of an implicit root observer. If the target was
+    // previously being tracked, but no longer needs to be tracked, then remove
+    // it.
+    if (target_->isConnected() && Observer()->RootIsImplicit() &&
         !observer_data->IsTargetOfImplicitRootObserver() &&
         !observer_data->IsRoot()) {
       IntersectionObserverController* controller =
diff --git a/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc b/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc
index c8b56a7..352eb48 100644
--- a/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc
+++ b/third_party/blink/renderer/core/intersection_observer/intersection_observer.cc
@@ -318,7 +318,8 @@
     // be recorded after observe() is called, even if the target is detached.
     observation->ComputeIntersection(
         IntersectionObservation::kImplicitRootObserversNeedUpdate |
-        IntersectionObservation::kExplicitRootObserversNeedUpdate);
+        IntersectionObservation::kExplicitRootObserversNeedUpdate |
+        IntersectionObservation::kIgnoreDelay);
   }
 }
 
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
index d562712..6a3777c0 100644
--- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
+++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.cc
@@ -20,6 +20,7 @@
 #include "third_party/blink/renderer/core/html/canvas/image_data.h"
 #include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h"
 #include "third_party/blink/renderer/core/workers/dedicated_worker_global_scope.h"
+#include "third_party/blink/renderer/platform/bindings/microtask.h"
 #include "third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h"
 #include "third_party/blink/renderer/platform/graphics/canvas_resource_provider.h"
 #include "third_party/blink/renderer/platform/graphics/gpu/shared_gpu_context.h"
@@ -34,17 +35,20 @@
 
 namespace blink {
 
-OffscreenCanvas::OffscreenCanvas(const IntSize& size)
+OffscreenCanvas::OffscreenCanvas(ExecutionContext* context, const IntSize& size)
     : CanvasRenderingContextHost(
           CanvasRenderingContextHost::HostType::kOffscreenCanvasHost),
+      execution_context_(context),
       size_(size) {
   UpdateMemoryUsage();
 }
 
-OffscreenCanvas* OffscreenCanvas::Create(unsigned width, unsigned height) {
+OffscreenCanvas* OffscreenCanvas::Create(ExecutionContext* context,
+                                         unsigned width,
+                                         unsigned height) {
   UMA_HISTOGRAM_BOOLEAN("Blink.OffscreenCanvas.NewOffscreenCanvas", true);
   return MakeGarbageCollected<OffscreenCanvas>(
-      IntSize(clampTo<int>(width), clampTo<int>(height)));
+      context, IntSize(clampTo<int>(width), clampTo<int>(height)));
 }
 
 OffscreenCanvas::~OffscreenCanvas() {
@@ -76,6 +80,10 @@
     context_ = nullptr;
   }
 
+  DeregisterFromAnimationFrameProvider();
+}
+
+void OffscreenCanvas::DeregisterFromAnimationFrameProvider() {
   if (HasPlaceholderCanvas() && GetTopExecutionContext() &&
       GetTopExecutionContext()->IsDedicatedWorkerGlobalScope()) {
     WorkerAnimationFrameProvider* animation_frame_provider =
@@ -93,6 +101,7 @@
     WorkerAnimationFrameProvider* animation_frame_provider =
         To<DedicatedWorkerGlobalScope>(GetTopExecutionContext())
             ->GetAnimationFrameProvider();
+    DCHECK(animation_frame_provider);
     if (animation_frame_provider)
       animation_frame_provider->RegisterOffscreenCanvas(this);
   }
@@ -111,25 +120,30 @@
 }
 
 void OffscreenCanvas::SetSize(const IntSize& size) {
+  // Setting size of a canvas also resets it.
+  if (size == size_) {
+    if (context_ && context_->Is2d()) {
+      context_->Reset();
+      origin_clean_ = true;
+    }
+    return;
+  }
+
+  size_ = size;
+  UpdateMemoryUsage();
+  current_frame_damage_rect_ = SkIRect::MakeWH(size_.Width(), size_.Height());
+
+  if (frame_dispatcher_)
+    frame_dispatcher_->Reshape(size_);
   if (context_) {
     if (context_->Is3d()) {
-      if (size != size_)
-        context_->Reshape(size.Width(), size.Height());
+      context_->Reshape(size_.Width(), size_.Height());
     } else if (context_->Is2d()) {
       context_->Reset();
       origin_clean_ = true;
     }
-  }
-  if (size != size_) {
-    UpdateMemoryUsage();
-  }
-  size_ = size;
-  if (frame_dispatcher_)
-    frame_dispatcher_->Reshape(size_);
-
-  current_frame_damage_rect_ = SkIRect::MakeWH(size_.Width(), size_.Height());
-  if (context_)
     context_->DidDraw();
+  }
 }
 
 void OffscreenCanvas::RecordTransfer() {
@@ -141,6 +155,7 @@
   is_neutered_ = true;
   size_.SetWidth(0);
   size_.SetHeight(0);
+  DeregisterFromAnimationFrameProvider();
 }
 
 ImageBitmap* OffscreenCanvas::transferToImageBitmap(
@@ -213,8 +228,7 @@
     ExecutionContext* execution_context,
     const String& id,
     const CanvasContextCreationAttributesCore& attributes) {
-  execution_context_ = execution_context;
-
+  DCHECK_EQ(execution_context, GetTopExecutionContext());
   CanvasRenderingContext::ContextType context_type =
       CanvasRenderingContext::ContextTypeFromId(id);
 
@@ -396,16 +410,17 @@
   }
 }
 
-void OffscreenCanvas::BeginFrame() {
+bool OffscreenCanvas::BeginFrame() {
   DCHECK(HasPlaceholderCanvas());
-  PushFrameIfNeeded();
   GetOrCreateResourceDispatcher()->SetNeedsBeginFrame(false);
+  return PushFrameIfNeeded();
 }
 
-void OffscreenCanvas::PushFrameIfNeeded() {
+bool OffscreenCanvas::PushFrameIfNeeded() {
   if (needs_push_frame_ && context_) {
-    context_->PushFrame();
+    return context_->PushFrame();
   }
+  return false;
 }
 
 bool OffscreenCanvas::ShouldAccelerate2dContext() const {
@@ -415,19 +430,21 @@
          context_provider_wrapper->Utils()->Accelerated2DCanvasFeatureEnabled();
 }
 
-void OffscreenCanvas::PushFrame(scoped_refptr<CanvasResource> canvas_resource,
+bool OffscreenCanvas::PushFrame(scoped_refptr<CanvasResource> canvas_resource,
                                 const SkIRect& damage_rect) {
+  TRACE_EVENT0("blink", "OffscreenCanvas::PushFrame");
   DCHECK(needs_push_frame_);
   needs_push_frame_ = false;
   current_frame_damage_rect_.join(damage_rect);
   if (current_frame_damage_rect_.isEmpty() || !canvas_resource)
-    return;
+    return false;
   const base::TimeTicks commit_start_time = base::TimeTicks::Now();
   GetOrCreateResourceDispatcher()->DispatchFrame(
       std::move(canvas_resource), commit_start_time, current_frame_damage_rect_,
       !RenderingContext()->IsOriginTopLeft() /* needs_vertical_flip */,
       IsOpaque());
   current_frame_damage_rect_ = SkIRect::MakeEmpty();
+  return true;
 }
 
 FontSelector* OffscreenCanvas::GetFontSelector() {
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h
index f9a9951..fb72bf6 100644
--- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h
+++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.h
@@ -46,9 +46,11 @@
   USING_PRE_FINALIZER(OffscreenCanvas, Dispose);
 
  public:
-  static OffscreenCanvas* Create(unsigned width, unsigned height);
+  static OffscreenCanvas* Create(ExecutionContext*,
+                                 unsigned width,
+                                 unsigned height);
 
-  explicit OffscreenCanvas(const IntSize&);
+  OffscreenCanvas(ExecutionContext*, const IntSize&);
   ~OffscreenCanvas() override;
   void Dispose();
 
@@ -60,7 +62,7 @@
   void setHeight(unsigned);
 
   // CanvasResourceDispatcherClient
-  void BeginFrame() override;
+  bool BeginFrame() override;
 
   // API Methods
   ImageBitmap* transferToImageBitmap(ScriptState*, ExceptionState&);
@@ -70,6 +72,7 @@
   void RecordTransfer();
 
   void SetPlaceholderCanvasId(DOMNodeId canvas_id);
+  void DeregisterFromAnimationFrameProvider();
   DOMNodeId PlaceholderCanvasId() const { return placeholder_canvas_id_; }
   bool HasPlaceholderCanvas() const;
   bool IsNeutered() const override { return is_neutered_; }
@@ -111,8 +114,9 @@
   void FinalizeFrame() override {}
   void DetachContext() override { context_ = nullptr; }
   CanvasRenderingContext* RenderingContext() const override { return context_; }
-  void PushFrameIfNeeded();
-  void PushFrame(scoped_refptr<CanvasResource> frame,
+
+  bool PushFrameIfNeeded();
+  bool PushFrame(scoped_refptr<CanvasResource> frame,
                  const SkIRect& damage_rect) override;
   void DidDraw(const FloatRect&) override;
   void DidDraw() override;
diff --git a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.idl b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.idl
index 767f6f5a..0890b3be 100644
--- a/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.idl
+++ b/third_party/blink/renderer/core/offscreencanvas/offscreen_canvas.idl
@@ -8,6 +8,7 @@
     Constructor([EnforceRange] unsigned long width, [EnforceRange] unsigned long height),
     Exposed=(Window,Worker),
     Transferable,
+    ConstructorCallWith=ExecutionContext,
     MeasureAs=OffscreenCanvas,
     RuntimeEnabled=SurfaceEmbeddingFeatures
 ] interface OffscreenCanvas : EventTarget {
diff --git a/third_party/blink/renderer/devtools/front_end/sdk/NetworkManager.js b/third_party/blink/renderer/devtools/front_end/sdk/NetworkManager.js
index 3736d24..4d94a2f 100644
--- a/third_party/blink/renderer/devtools/front_end/sdk/NetworkManager.js
+++ b/third_party/blink/renderer/devtools/front_end/sdk/NetworkManager.js
@@ -328,8 +328,8 @@
       networkRequest.setTransferSize(response.encodedDataLength);
 
     if (response.requestHeaders && !networkRequest.hasExtraRequestInfo()) {
-      // TODO(http://crbug.com/991471): Stop using response.requestHeaders and
-      //   response.requestHeadersText once service workers and shared workers
+      // TODO(http://crbug.com/1004979): Stop using response.requestHeaders and
+      //   response.requestHeadersText once shared workers
       //   emit Network.*ExtraInfo events for their network requests.
       networkRequest.setRequestHeaders(this._headersMapToHeadersArray(response.requestHeaders));
       networkRequest.setRequestHeadersText(response.requestHeadersText || '');
diff --git a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc
index 8c99835..3a7cbe98 100644
--- a/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc
+++ b/third_party/blink/renderer/modules/canvas/canvas2d/canvas_rendering_context_2d_state.cc
@@ -8,6 +8,7 @@
 #include "third_party/blink/renderer/core/css/resolver/filter_operation_resolver.h"
 #include "third_party/blink/renderer/core/css/resolver/style_builder.h"
 #include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
+#include "third_party/blink/renderer/core/dom/node_computed_style.h"
 #include "third_party/blink/renderer/core/html/canvas/html_canvas_element.h"
 #include "third_party/blink/renderer/core/paint/filter_effect_builder.h"
 #include "third_party/blink/renderer/core/style/computed_style.h"
@@ -334,8 +335,18 @@
 
     scoped_refptr<ComputedStyle> filter_style = ComputedStyle::Create();
     // Must set font in case the filter uses any font-relative units (em, ex)
-    filter_style->SetFont(font_for_filter_);
-
+    // If font_for_filter_ was never set (ie frame-less documents) use base font
+    if (LIKELY(font_for_filter_.GetFontSelector())) {
+      filter_style->SetFont(font_for_filter_);
+    } else {
+      const ComputedStyle* computed_style =
+          style_resolution_host->GetDocument().GetComputedStyle();
+      if (computed_style) {
+        filter_style->SetFont(computed_style->GetFont());
+      } else {
+        return nullptr;
+      }
+    }
     StyleResolverState resolver_state(style_resolution_host->GetDocument(),
                                       *style_resolution_host,
                                       filter_style.get(), filter_style.get());
diff --git a/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.cc b/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.cc
index 7fe743a8..66271ef4c 100644
--- a/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.cc
+++ b/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.cc
@@ -37,6 +37,7 @@
 }
 
 OffscreenCanvas* HTMLCanvasElementModule::transferControlToOffscreen(
+    ExecutionContext* execution_context,
     HTMLCanvasElement& canvas,
     ExceptionState& exception_state) {
   OffscreenCanvas* offscreen_canvas = nullptr;
@@ -46,8 +47,8 @@
         "Cannot transfer control from a canvas for more than one time.");
   } else {
     canvas.CreateLayer();
-    offscreen_canvas =
-        TransferControlToOffscreenInternal(canvas, exception_state);
+    offscreen_canvas = TransferControlToOffscreenInternal(
+        execution_context, canvas, exception_state);
   }
 
   UMA_HISTOGRAM_BOOLEAN("Blink.OffscreenCanvas.TransferControlToOffscreen",
@@ -56,6 +57,7 @@
 }
 
 OffscreenCanvas* HTMLCanvasElementModule::TransferControlToOffscreenInternal(
+    ExecutionContext* execution_context,
     HTMLCanvasElement& canvas,
     ExceptionState& exception_state) {
   if (canvas.RenderingContext()) {
@@ -64,8 +66,8 @@
         "Cannot transfer control from a canvas that has a rendering context.");
     return nullptr;
   }
-  OffscreenCanvas* offscreen_canvas =
-      OffscreenCanvas::Create(canvas.width(), canvas.height());
+  OffscreenCanvas* offscreen_canvas = OffscreenCanvas::Create(
+      execution_context, canvas.width(), canvas.height());
   offscreen_canvas->SetFilterQuality(canvas.FilterQuality());
 
   // If this canvas is cross-origin, then the associated offscreen canvas
diff --git a/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.h b/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.h
index 2752cff..85dff709 100644
--- a/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.h
+++ b/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.h
@@ -26,11 +26,13 @@
                          const CanvasContextCreationAttributesModule*,
                          ExceptionState&,
                          RenderingContext&);
-  static OffscreenCanvas* transferControlToOffscreen(HTMLCanvasElement&,
+  static OffscreenCanvas* transferControlToOffscreen(ExecutionContext*,
+                                                     HTMLCanvasElement&,
                                                      ExceptionState&);
 
  private:
-  static OffscreenCanvas* TransferControlToOffscreenInternal(HTMLCanvasElement&,
+  static OffscreenCanvas* TransferControlToOffscreenInternal(ExecutionContext*,
+                                                             HTMLCanvasElement&,
                                                              ExceptionState&);
 };
 }  // namespace blink
diff --git a/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.idl b/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.idl
index c342789..1c40f9ae 100644
--- a/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.idl
+++ b/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module.idl
@@ -24,6 +24,6 @@
     // Related spec issue: https://github.com/whatwg/html/issues/595
     [RaisesException] RenderingContext? getContext(DOMString contextId, [PermissiveDictionaryConversion] optional CanvasContextCreationAttributesModule attributes);
 
-    [RuntimeEnabled=SurfaceEmbeddingFeatures,
+    [CallWith=ExecutionContext, RuntimeEnabled=SurfaceEmbeddingFeatures,
      RaisesException, MeasureAs=OffscreenCanvas] OffscreenCanvas transferControlToOffscreen();
 };
diff --git a/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_support_webgl2_compute.idl b/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_support_webgl2_compute.idl
index 60d6efd..3ca7190 100644
--- a/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_support_webgl2_compute.idl
+++ b/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_support_webgl2_compute.idl
@@ -24,5 +24,5 @@
     // (and is not undefined or null). The binding must ignore this.
     // Related spec issue: https://github.com/whatwg/html/issues/595
     [RaisesException] RenderingContext? getContext(DOMString contextId, [PermissiveDictionaryConversion] optional CanvasContextCreationAttributesModule attributes);
-    [RaisesException, MeasureAs=OffscreenCanvas, RuntimeEnabled=SurfaceEmbeddingFeatures] OffscreenCanvas transferControlToOffscreen();
+    [CallWith=ExecutionContext, RaisesException, MeasureAs=OffscreenCanvas, RuntimeEnabled=SurfaceEmbeddingFeatures] OffscreenCanvas transferControlToOffscreen();
 };
diff --git a/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc b/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc
index d2562abc..89efe0d 100644
--- a/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc
+++ b/third_party/blink/renderer/modules/canvas/htmlcanvas/html_canvas_element_module_test.cc
@@ -10,6 +10,7 @@
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "third_party/blink/public/mojom/frame_sinks/embedded_frame_sink.mojom-blink.h"
+#include "third_party/blink/renderer/bindings/core/v8/v8_binding_for_testing.h"
 #include "third_party/blink/renderer/core/dom/document.h"
 #include "third_party/blink/renderer/core/dom/dom_node_ids.h"
 #include "third_party/blink/renderer/core/frame/frame_test_helpers.h"
@@ -67,7 +68,7 @@
   HTMLCanvasElement& canvas_element() const { return *canvas_element_; }
   OffscreenCanvas* TransferControlToOffscreen(ExceptionState& exception_state) {
     return HTMLCanvasElementModule::TransferControlToOffscreenInternal(
-        canvas_element(), exception_state);
+        &GetDocument(), canvas_element(), exception_state);
   }
 
   frame_test_helpers::WebViewHelper web_view_helper_;
diff --git a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.cc b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.cc
index f43ed0d..c44ddbb 100644
--- a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.cc
@@ -99,11 +99,11 @@
   return !!static_cast<OffscreenCanvas*>(Host())->GetOrCreateResourceProvider();
 }
 
-void ImageBitmapRenderingContextBase::PushFrame() {
+bool ImageBitmapRenderingContextBase::PushFrame() {
   DCHECK(Host());
   DCHECK(Host()->IsOffscreenCanvas());
   if (!CanCreateCanvas2dResourceProvider())
-    return;
+    return false;
 
   scoped_refptr<StaticBitmapImage> image = image_layer_bridge_->GetImage();
   cc::PaintFlags paint_flags;
@@ -116,6 +116,7 @@
       std::move(resource),
       SkIRect::MakeWH(image_layer_bridge_->GetImage()->Size().Width(),
                       image_layer_bridge_->GetImage()->Size().Height()));
+  return true;
 }
 
 bool ImageBitmapRenderingContextBase::IsOriginTopLeft() const {
diff --git a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.h b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.h
index 7cb61cd..b5dd9d10 100644
--- a/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.h
+++ b/third_party/blink/renderer/modules/canvas/imagebitmap/image_bitmap_rendering_context_base.h
@@ -53,7 +53,7 @@
   void SetUV(const FloatPoint& left_top, const FloatPoint& right_bottom);
   bool IsComposited() const final { return true; }
   bool IsAccelerated() const final;
-  void PushFrame() override;
+  bool PushFrame() override;
 
   bool IsOriginTopLeft() const override;
 
diff --git a/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc b/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc
index 3c90dfbb..025d75d 100644
--- a/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc
+++ b/third_party/blink/renderer/modules/canvas/offscreencanvas/offscreen_canvas_test.cc
@@ -92,7 +92,7 @@
 
   DummyExceptionStateForTesting exception_state;
   offscreen_canvas_ = HTMLCanvasElementModule::transferControlToOffscreen(
-      *canvas_element, exception_state);
+      &GetDocument(), *canvas_element, exception_state);
   // |offscreen_canvas_| should inherit the FrameSinkId from |canvas_element|s
   // SurfaceLayerBridge, but in tests this id is zero; fill it up by hand.
   offscreen_canvas_->SetFrameSinkId(kClientId, kSinkId);
diff --git a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc
index c8f1af1..37b68d6c 100644
--- a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc
+++ b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.cc
@@ -159,14 +159,15 @@
   return frame;
 }
 
-void OffscreenCanvasRenderingContext2D::PushFrame() {
+bool OffscreenCanvasRenderingContext2D::PushFrame() {
   if (dirty_rect_for_commit_.isEmpty())
-    return;
+    return false;
 
   SkIRect damage_rect(dirty_rect_for_commit_);
-  Host()->PushFrame(ProduceCanvasResource(), damage_rect);
+  bool ret = Host()->PushFrame(ProduceCanvasResource(), damage_rect);
   dirty_rect_for_commit_.setEmpty();
   GetOffscreenFontCache().PruneLocalFontCache(kMaxCachedFonts);
+  return ret;
 }
 
 ImageBitmap* OffscreenCanvasRenderingContext2D::TransferToImageBitmap(
diff --git a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h
index 248c961..56ea10b 100644
--- a/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h
+++ b/third_party/blink/renderer/modules/canvas/offscreencanvas2d/offscreen_canvas_rendering_context_2d.h
@@ -118,7 +118,7 @@
 
   void Trace(blink::Visitor*) override;
 
-  void PushFrame() override;
+  bool PushFrame() override;
 
  protected:
   void NeedsFinalizeFrame() override {
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
index a009ccb..056bae68 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
@@ -1396,16 +1396,19 @@
   CanvasRenderingContext::DidDraw();
 }
 
-void WebGLRenderingContextBase::PushFrame() {
+bool WebGLRenderingContextBase::PushFrame() {
   int width = GetDrawingBuffer()->Size().Width();
   int height = GetDrawingBuffer()->Size().Height();
+  int submitted_frame = false;
   if (PaintRenderingResultsToCanvas(kBackBuffer)) {
     if (Host()->GetOrCreateCanvasResourceProvider(kPreferAcceleration)) {
-      Host()->PushFrame(Host()->ResourceProvider()->ProduceCanvasResource(),
-                        SkIRect::MakeWH(width, height));
+      submitted_frame =
+          Host()->PushFrame(Host()->ResourceProvider()->ProduceCanvasResource(),
+                            SkIRect::MakeWH(width, height));
     }
   }
   MarkLayerComposited();
+  return submitted_frame;
 }
 
 void WebGLRenderingContextBase::FinalizeFrame() {
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
index c2fc04a..1ac94d0 100644
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.h
@@ -669,7 +669,7 @@
   void DidDraw(const SkIRect&) override;
   void DidDraw() override;
   void FinalizeFrame() override;
-  void PushFrame() override;
+  bool PushFrame() override;
 
   // DrawingBuffer::Client implementation.
   bool DrawingBufferClientIsBoundForDraw() override;
diff --git a/third_party/blink/renderer/modules/xr/xr.cc b/third_party/blink/renderer/modules/xr/xr.cc
index 7c7f5f6..a14682ba 100644
--- a/third_party/blink/renderer/modules/xr/xr.cc
+++ b/third_party/blink/renderer/modules/xr/xr.cc
@@ -230,15 +230,28 @@
 
 XR::PendingSupportsSessionQuery::PendingSupportsSessionQuery(
     ScriptPromiseResolver* resolver,
-    XRSession::SessionMode session_mode)
-    : resolver_(resolver), mode_(session_mode) {}
+    XRSession::SessionMode session_mode,
+    bool throw_on_unsupported)
+    : resolver_(resolver),
+      mode_(session_mode),
+      throw_on_unsupported_(throw_on_unsupported) {}
 
 void XR::PendingSupportsSessionQuery::Trace(blink::Visitor* visitor) {
   visitor->Trace(resolver_);
 }
 
-void XR::PendingSupportsSessionQuery::Resolve() {
-  resolver_->Resolve();
+void XR::PendingSupportsSessionQuery::Resolve(bool supported,
+                                              ExceptionState* exception_state) {
+  if (throw_on_unsupported_) {
+    if (supported) {
+      resolver_->Resolve();
+    } else {
+      RejectWithDOMException(DOMExceptionCode::kNotSupportedError,
+                             kSessionNotSupported, exception_state);
+    }
+  } else {
+    resolver_->Resolve(supported);
+  }
 }
 
 void XR::PendingSupportsSessionQuery::RejectWithDOMException(
@@ -485,6 +498,19 @@
 ScriptPromise XR::supportsSession(ScriptState* script_state,
                                   const String& mode,
                                   ExceptionState& exception_state) {
+  return InternalIsSessionSupported(script_state, mode, exception_state, true);
+}
+
+ScriptPromise XR::isSessionSupported(ScriptState* script_state,
+                                     const String& mode,
+                                     ExceptionState& exception_state) {
+  return InternalIsSessionSupported(script_state, mode, exception_state, false);
+}
+
+ScriptPromise XR::InternalIsSessionSupported(ScriptState* script_state,
+                                             const String& mode,
+                                             ExceptionState& exception_state,
+                                             bool throw_on_unsupported) {
   LocalFrame* frame = GetFrame();
   Document* doc = frame ? frame->GetDocument() : nullptr;
   if (!doc) {
@@ -499,7 +525,8 @@
 
   XRSession::SessionMode session_mode = stringToSessionMode(mode);
   PendingSupportsSessionQuery* query =
-      MakeGarbageCollected<PendingSupportsSessionQuery>(resolver, session_mode);
+      MakeGarbageCollected<PendingSupportsSessionQuery>(resolver, session_mode,
+                                                        throw_on_unsupported);
 
   if (session_mode == XRSession::kModeImmersiveAR &&
       !RuntimeEnabledFeatures::WebXRARModuleEnabled(doc)) {
@@ -519,13 +546,12 @@
 
   if (session_mode == XRSession::kModeInline) {
     // `inline` sessions are always supported if not blocked by feature policy.
-    query->Resolve();
+    query->Resolve(true);
   } else {
     if (!service_) {
       // If we don't have a service at the time we reach this call it indicates
       // that there's no WebXR hardware. Reject as not supported.
-      query->RejectWithDOMException(DOMExceptionCode::kNotSupportedError,
-                                    kSessionNotSupported, &exception_state);
+      query->Resolve(false, &exception_state);
       return promise;
     }
 
@@ -750,13 +776,7 @@
   // promise, so remove it from our outstanding list.
   DCHECK(outstanding_support_queries_.Contains(query));
   outstanding_support_queries_.erase(query);
-
-  if (supports_session) {
-    query->Resolve();
-  } else {
-    query->RejectWithDOMException(DOMExceptionCode::kNotSupportedError,
-                                  kSessionNotSupported, nullptr);
-  }
+  query->Resolve(supports_session);
 }
 
 void XR::OnRequestSessionReturned(
diff --git a/third_party/blink/renderer/modules/xr/xr.h b/third_party/blink/renderer/modules/xr/xr.h
index 6b1818b1..d79a31b 100644
--- a/third_party/blink/renderer/modules/xr/xr.h
+++ b/third_party/blink/renderer/modules/xr/xr.h
@@ -46,6 +46,9 @@
   ScriptPromise supportsSession(ScriptState*,
                                 const String&,
                                 ExceptionState& exception_state);
+  ScriptPromise isSessionSupported(ScriptState*,
+                                   const String&,
+                                   ExceptionState& exception_state);
   ScriptPromise requestSession(ScriptState*,
                                const String&,
                                XRSessionInit*,
@@ -177,11 +180,13 @@
   class PendingSupportsSessionQuery final
       : public GarbageCollected<PendingSupportsSessionQuery> {
    public:
-    PendingSupportsSessionQuery(ScriptPromiseResolver*, XRSession::SessionMode);
+    PendingSupportsSessionQuery(ScriptPromiseResolver*,
+                                XRSession::SessionMode,
+                                bool throw_on_unsupported);
     virtual ~PendingSupportsSessionQuery() = default;
 
     // Resolves underlying promise.
-    void Resolve();
+    void Resolve(bool supported, ExceptionState* exception_state = nullptr);
 
     // Rejects underlying promise with a DOMException.
     // Do not call this with |DOMExceptionCode::kSecurityError|, use
@@ -204,6 +209,8 @@
     void RejectWithTypeError(const String& message,
                              ExceptionState* exception_state);
 
+    bool ThrowOnUnsupported() const { return throw_on_unsupported_; }
+
     XRSession::SessionMode mode() const;
 
     virtual void Trace(blink::Visitor*);
@@ -212,9 +219,17 @@
     Member<ScriptPromiseResolver> resolver_;
     const XRSession::SessionMode mode_;
 
+    // Only set when calling the deprecated supportsSession method.
+    const bool throw_on_unsupported_ = false;
+
     DISALLOW_COPY_AND_ASSIGN(PendingSupportsSessionQuery);
   };
 
+  ScriptPromise InternalIsSessionSupported(ScriptState*,
+                                           const String&,
+                                           ExceptionState& exception_state,
+                                           bool throw_on_unsupported);
+
   const char* CheckInlineSessionRequestAllowed(
       LocalFrame* frame,
       Document* doc,
diff --git a/third_party/blink/renderer/modules/xr/xr.idl b/third_party/blink/renderer/modules/xr/xr.idl
index a1dab89..93aba883d 100644
--- a/third_party/blink/renderer/modules/xr/xr.idl
+++ b/third_party/blink/renderer/modules/xr/xr.idl
@@ -9,6 +9,7 @@
     RuntimeEnabled=WebXR
 ] interface XR : EventTarget {
   attribute EventHandler ondevicechange;
-  [CallWith=ScriptState, MeasureAs=XRSupportsSession, RaisesException] Promise<void> supportsSession(XRSessionMode mode);
+  [CallWith=ScriptState, DeprecateAs=XRSupportsSession, RaisesException] Promise<void> supportsSession(XRSessionMode mode);
+  [CallWith=ScriptState, MeasureAs=XRIsSessionSupported, RaisesException] Promise<boolean> isSessionSupported(XRSessionMode mode);
   [CallWith=ScriptState, MeasureAs=XRRequestSession, RaisesException] Promise<XRSession> requestSession(XRSessionMode mode, optional XRSessionInit options);
 };
diff --git a/third_party/blink/renderer/platform/blob/blob_data.cc b/third_party/blink/renderer/platform/blob/blob_data.cc
index 789ac4a..f88c3d4 100644
--- a/third_party/blink/renderer/platform/blob/blob_data.cc
+++ b/third_party/blink/renderer/platform/blob/blob_data.cc
@@ -374,6 +374,16 @@
   return blob_clone;
 }
 
+void BlobDataHandle::CloneBlobRemote(
+    mojo::PendingReceiver<mojom::blink::Blob> receiver) {
+  MutexLocker locker(blob_remote_mutex_);
+  if (!blob_remote_.is_valid())
+    return;
+  mojo::Remote<mojom::blink::Blob> blob(std::move(blob_remote_));
+  blob->Clone(std::move(receiver));
+  blob_remote_ = blob.Unbind();
+}
+
 mojo::PendingRemote<network::mojom::blink::DataPipeGetter>
 BlobDataHandle::AsDataPipeGetter() {
   MutexLocker locker(blob_remote_mutex_);
diff --git a/third_party/blink/renderer/platform/blob/blob_data.h b/third_party/blink/renderer/platform/blob/blob_data.h
index 76f042c..9ae3614 100644
--- a/third_party/blink/renderer/platform/blob/blob_data.h
+++ b/third_party/blink/renderer/platform/blob/blob_data.h
@@ -208,6 +208,7 @@
   ~BlobDataHandle();
 
   mojo::PendingRemote<mojom::blink::Blob> CloneBlobRemote();
+  void CloneBlobRemote(mojo::PendingReceiver<mojom::blink::Blob>);
   mojo::PendingRemote<network::mojom::blink::DataPipeGetter> AsDataPipeGetter();
 
   void ReadAll(mojo::ScopedDataPipeProducerHandle,
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 e134ad7..1d8ddf5 100644
--- a/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc
+++ b/third_party/blink/renderer/platform/graphics/begin_frame_provider.cc
@@ -95,10 +95,15 @@
 void BeginFrameProvider::OnBeginFrame(
     const viz::BeginFrameArgs& args,
     WTF::HashMap<uint32_t, ::viz::mojom::blink::FrameTimingDetailsPtr>) {
+  if (args.deadline < base::TimeTicks::Now()) {
+    compositor_frame_sink_->DidNotProduceFrame(viz::BeginFrameAck(args, false));
+    return;
+  }
+
   // If there was no need for a BeginFrame, just skip it.
   if (needs_begin_frame_ && requested_needs_begin_frame_) {
     requested_needs_begin_frame_ = false;
-    begin_frame_client_->BeginFrame();
+    begin_frame_client_->BeginFrame(args.frame_time);
   } else {
     if (!requested_needs_begin_frame_) {
       needs_begin_frame_ = false;
diff --git a/third_party/blink/renderer/platform/graphics/begin_frame_provider.h b/third_party/blink/renderer/platform/graphics/begin_frame_provider.h
index af52da0..6c4a271 100644
--- a/third_party/blink/renderer/platform/graphics/begin_frame_provider.h
+++ b/third_party/blink/renderer/platform/graphics/begin_frame_provider.h
@@ -24,7 +24,7 @@
 
 class PLATFORM_EXPORT BeginFrameProviderClient {
  public:
-  virtual void BeginFrame() = 0;
+  virtual void BeginFrame(const base::TimeTicks& frame_time) = 0;
   virtual ~BeginFrameProviderClient() = default;
 };
 
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc
index d4b089d2..854ca890 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.cc
@@ -332,9 +332,16 @@
     return;
   }
 
-  if (Client())
-    Client()->BeginFrame();
-  // TODO(eseckler): Tell |sink_| if we did not draw during the BeginFrame.
+  // TODO(fserb): should EnqueueMicrotask BeginFrame().
+  // We usually never get to BeginFrame if we are on RAF mode. But it could
+  // still happen that begin frame gets requested and we don't have a frame
+  // anymore, so we shouldn't let the compositor wait.
+  bool submitted_frame = Client() && Client()->BeginFrame();
+  if (!submitted_frame) {
+    sink_->DidNotProduceFrame(current_begin_frame_ack_);
+  }
+
+  // TODO(fserb): Update this with the correct value if we are on RAF submit.
   current_begin_frame_ack_.sequence_number =
       viz::BeginFrameArgs::kInvalidFrameNumber;
 }
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h
index fef3d71..018ac27 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_dispatcher.h
@@ -22,7 +22,7 @@
 
 class CanvasResourceDispatcherClient {
  public:
-  virtual void BeginFrame() = 0;
+  virtual bool BeginFrame() = 0;
 };
 
 class PLATFORM_EXPORT CanvasResourceDispatcher
diff --git a/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc b/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc
index 2a891c9..235a0718 100644
--- a/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc
+++ b/third_party/blink/renderer/platform/graphics/canvas_resource_provider_test.cc
@@ -32,7 +32,7 @@
  public:
   MockCanvasResourceDispatcherClient() = default;
 
-  MOCK_METHOD0(BeginFrame, void());
+  MOCK_METHOD0(BeginFrame, bool());
 };
 
 class MockWebGraphisContext3DProviderWrapper
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
index 967db79..288f8ef 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.cc
@@ -97,7 +97,7 @@
   if (is_backgrounded) {
     return "renderer_backgrounded";
   } else {
-    return "renderer_visible";
+    return "renderer_foregrounded";
   }
 }
 
@@ -371,12 +371,12 @@
                             &main_thread_scheduler_impl->tracing_controller_,
                             RAILModeToString),
       renderer_hidden(false,
-                      "Scheduler.Hidden",
+                      "RendererVisibility",
                       main_thread_scheduler_impl,
                       &main_thread_scheduler_impl->tracing_controller_,
                       HiddenStateToString),
       renderer_backgrounded(kLaunchingProcessIsBackgrounded,
-                            "RendererVisibility",
+                            "RendererPriority",
                             main_thread_scheduler_impl,
                             &main_thread_scheduler_impl->tracing_controller_,
                             BackgroundStateToString),
diff --git a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
index 6b2b35e..26970c3 100644
--- a/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
+++ b/third_party/blink/renderer/platform/scheduler/main_thread/main_thread_scheduler_impl.h
@@ -853,7 +853,7 @@
         renderer_pause_count;  // Renderer is paused if non-zero.
     TraceableState<RAILMode, TracingCategoryName::kInfo>
         rail_mode_for_tracing;  // Don't use except for tracing.
-    TraceableState<bool, TracingCategoryName::kDebug> renderer_hidden;
+    TraceableState<bool, TracingCategoryName::kTopLevel> renderer_hidden;
     TraceableState<bool, TracingCategoryName::kTopLevel> renderer_backgrounded;
     TraceableState<bool, TracingCategoryName::kDefault>
         keep_active_fetch_or_worker;
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations
index 81f62043..bccd2ee 100644
--- a/third_party/blink/web_tests/TestExpectations
+++ b/third_party/blink/web_tests/TestExpectations
@@ -5975,6 +5975,7 @@
 # Sheriff 2019-07-04
 crbug.com/981267 [ Linux ] http/tests/devtools/persistence/persistence-move-breakpoints-on-reload.js [ Pass Failure ]
 crbug.com/981303 [ Mac ] http/tests/media/controls/toggle-class-with-state-source.html [ Pass Timeout ]
+crbug.com/981303 [ Mac ] virtual/audio-service/http/tests/media/controls/toggle-class-with-state-source.html [ Pass Timeout ]
 crbug.com/981331 fast/forms/form-submission-create-crash.xhtml [ Pass Timeout ]
 # TODO(crbug.com/980588): reenable once WPT is fixed
 crbug.com/980588 external/wpt/screen-orientation/lock-unlock-check.html [ Pass Failure ]
diff --git a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
index 564f6b12..6e37ed2 100644
--- a/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
+++ b/third_party/blink/web_tests/external/WPT_BASE_MANIFEST_6.json
@@ -124984,6 +124984,9 @@
    "content-security-policy/frame-ancestors/support/frame-in-frame.sub.html.sub.headers": [
     []
    ],
+   "content-security-policy/frame-ancestors/support/service-worker.js": [
+    []
+   ],
    "content-security-policy/frame-src/frame-src-redirect.html.headers": [
     []
    ],
@@ -153430,7 +153433,7 @@
    "fonts/CanvasTest.ttf": [
     []
    ],
-   "fonts/CanvasTest.ttf.sub.headers": [
+   "fonts/CanvasTest.ttf.headers": [
     []
    ],
    "fonts/GentiumPlus-R.woff": [
@@ -153502,6 +153505,9 @@
    "fonts/ahem.css": [
     []
    ],
+   "fonts/ahem.css.headers": [
+    []
+   ],
    "fonts/math/axisheight5000-verticalarrow14000.woff": [
     []
    ],
@@ -175762,9 +175768,6 @@
    "webrtc-stats/getStats-remote-candidate-address-expected.txt": [
     []
    ],
-   "webrtc-stats/idlharness.window-expected.txt": [
-    []
-   ],
    "webrtc-svc/RTCRtpParameters-scalability-expected.txt": [
     []
    ],
@@ -198061,6 +198064,12 @@
      {}
     ]
    ],
+   "content-security-policy/frame-ancestors/frame-ancestors-from-serviceworker.https.html": [
+    [
+     "content-security-policy/frame-ancestors/frame-ancestors-from-serviceworker.https.html",
+     {}
+    ]
+   ],
    "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-none-block.html": [
     [
      "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-none-block.html",
@@ -330641,6 +330650,10 @@
    "63e464be21a0fea5fb1d2ae6b4df45cd29c0f2dd",
    "support"
   ],
+  "content-security-policy/frame-ancestors/frame-ancestors-from-serviceworker.https.html": [
+   "bf0e9d54102de36da4c005f8652ae5440cacab2d",
+   "testharness"
+  ],
   "content-security-policy/frame-ancestors/frame-ancestors-nested-cross-in-cross-none-block.html": [
    "674deb655a75c07ec9c06cc608bbb5e523bbea18",
    "testharness"
@@ -330797,6 +330810,10 @@
    "e853d6cee5e0cb25824545284a7233497159a70c",
    "support"
   ],
+  "content-security-policy/frame-ancestors/support/service-worker.js": [
+   "ebced90f50af06b174655b1d0ab0edcfe472e010",
+   "support"
+  ],
   "content-security-policy/frame-src/frame-src-about-blank-allowed-by-default.sub.html": [
    "8211d0847a8ef97c0177353ab8308a8b0b0d9a60",
    "testharness"
@@ -429042,7 +429059,7 @@
    "support"
   ],
   "fonts/Ahem.ttf.headers": [
-   "cb762eff806849df46dc758ef7b98b63f27f54c9",
+   "659e3760fba9ee28df2a8bebb8bc27905b2ae0a3",
    "support"
   ],
   "fonts/CSSTest/LICENSE": [
@@ -429265,8 +429282,8 @@
    "9023592ef5aa83a03dd6957398897a585062ca57",
    "support"
   ],
-  "fonts/CanvasTest.ttf.sub.headers": [
-   "360e6686bfb65ed33d811d15e1ba7183a736d552",
+  "fonts/CanvasTest.ttf.headers": [
+   "6f34caa8f2ab5dee8a48caa58048218896dc9049",
    "support"
   ],
   "fonts/GentiumPlus-R.woff": [
@@ -429361,6 +429378,10 @@
    "b278cc14c54af7f6a2d893c6453778bceb65a8ce",
    "support"
   ],
+  "fonts/ahem.css.headers": [
+   "e828b629858d07afd989b80894986315bac16cc7",
+   "support"
+  ],
   "fonts/math/axisheight5000-verticalarrow14000.woff": [
    "9f5d59ae6a7fbf221fd14126645f1cbc7c25d286",
    "support"
@@ -430250,7 +430271,7 @@
    "testharness"
   ],
   "generic-sensor/resources/generic-sensor-helpers.js": [
-   "8302f6f6cfbc77ebda6ab92f5a1269fb209416c1",
+   "afc2fadec9d8da2771424e72f17e38f5b633adad",
    "support"
   ],
   "generic-sensor/resources/iframe_sensor_handler.html": [
@@ -452218,7 +452239,7 @@
    "support"
   ],
   "interfaces/encoding.idl": [
-   "c89cad4f9a154c467224e3becbd8b12fcb8a1f23",
+   "d4fffa89334b1e79f4966769e1d0cf9fb17378aa",
    "support"
   ],
   "interfaces/encrypted-media.idl": [
@@ -452590,7 +452611,7 @@
    "support"
   ],
   "interfaces/webrtc.idl": [
-   "f56ff80389007129f843eb998c9d2f6a6ca44a33",
+   "b8657386f9cea8e0587ebca3ab92b0eb76a70cc8",
    "support"
   ],
   "interfaces/webusb.idl": [
@@ -453178,7 +453199,7 @@
    "testharness"
   ],
   "layout-instability/observe-layout-shift.html": [
-   "8e5624e09a3d92975f315f7601c8cfc474c89c9e",
+   "1c35fe2aa234c96fce8798e6a1c35362f418e6f1",
    "testharness"
   ],
   "layout-instability/resources/slow-image.py": [
@@ -479246,7 +479267,7 @@
    "support"
   ],
   "resources/chromium/generic_sensor_mocks.js": [
-   "4f1370236876f4d6a919e3fad1175eaef6ae2850",
+   "a7272a65fa3e7f20b31310751278dfb8744146f0",
    "support"
   ],
   "resources/chromium/generic_sensor_mocks.js.headers": [
@@ -498893,10 +498914,6 @@
    "bf580688591dbce35ef852c511d2c6b2dc01ab8b",
    "testharness"
   ],
-  "webrtc-stats/idlharness.window-expected.txt": [
-   "1c7c1ea47a758f2b6f975e676fd9dc9a21a52bc6",
-   "support"
-  ],
   "webrtc-stats/idlharness.window.js": [
    "d98712fc485298a0455e44c9f29407dc232fca63",
    "testharness"
@@ -499546,7 +499563,7 @@
    "testharness"
   ],
   "webrtc/idlharness.https.window-expected.txt": [
-   "1049e1a86cc696ae76b7c30523bc912fda72757b",
+   "4a3962ded4ed6bdc2cc48e0b3b6fab33ccaa8ffc",
    "support"
   ],
   "webrtc/idlharness.https.window.js": [
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/frame-ancestors/frame-ancestors-from-serviceworker.https.html b/third_party/blink/web_tests/external/wpt/content-security-policy/frame-ancestors/frame-ancestors-from-serviceworker.https.html
new file mode 100644
index 0000000..bf0e9d5
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/frame-ancestors/frame-ancestors-from-serviceworker.https.html
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+  <script src="/resources/testharness.js"></script>
+  <script src="/resources/testharnessreport.js"></script>
+  <script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
+</head>
+<body>
+  <script>
+    var t = async_test("A 'frame-ancestors' CSP directive set from a serviceworker response with a value 'none' should block rendering.");
+
+    // Register service worker.
+    var worker = 'support/service-worker.js';
+    var scope = 'support/service-worker/';
+    service_worker_unregister_and_register(t, worker, scope)
+      .then(registration => wait_for_state(t, registration.installing, 'activated'))
+      .then(() => {
+        // Load iframe.
+        var iframe = document.createElement("iframe");
+        function iframeLoaded(ev) {
+          var failed = false;
+          try {
+            ev.target.contentWindow.location.href;
+            failed = true;
+          } catch (ex) {}
+          t.step_func_done(() => assert_false(failed, "The IFrame should have been blocked. It wasn't."))();
+        };
+        iframe.addEventListener("load", iframeLoaded);
+        iframe.addEventListener("error", iframeLoaded);
+        iframe.src = "/content-security-policy/frame-ancestors/support/service-worker/frame-ancestors-none.html";
+        document.body.appendChild(iframe);
+      });
+  </script>
+</body>
+</html>
+
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/frame-ancestors/report-blocked-frame.sub.html b/third_party/blink/web_tests/external/wpt/content-security-policy/frame-ancestors/report-blocked-frame.sub.html
index 047d377..69c098d 100644
--- a/third_party/blink/web_tests/external/wpt/content-security-policy/frame-ancestors/report-blocked-frame.sub.html
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/frame-ancestors/report-blocked-frame.sub.html
@@ -1,5 +1,6 @@
 <!DOCTYPE html>
 <html>
+<meta name="timeout" content="long">
 <head>
   <script src="/resources/testharness.js"></script>
   <script src="/resources/testharnessreport.js"></script>
diff --git a/third_party/blink/web_tests/external/wpt/content-security-policy/frame-ancestors/support/service-worker.js b/third_party/blink/web_tests/external/wpt/content-security-policy/frame-ancestors/support/service-worker.js
new file mode 100644
index 0000000..ebced90
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/content-security-policy/frame-ancestors/support/service-worker.js
@@ -0,0 +1,10 @@
+self.onfetch = e => {
+  e.respondWith(function() {
+    return new Promise((resolve) => {
+      var headers = new Headers;
+      headers.append("Content-Security-Policy", "frame-ancestors 'none'");
+      var response = new Response("", { "headers" : headers, "status": 200, "statusText" : "OK" });
+      resolve(response);
+    });
+  }());
+};
diff --git a/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-computed.html b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-computed.html
new file mode 100644
index 0000000..467f435
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-animations/parsing/animation-computed.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Animations: getComputedStyle().animation</title>
+<link rel="help" href="https://drafts.csswg.org/css-animations/#propdef-animation">
+<meta name="assert" content="animation computed value is as specified.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+// <single-animation> = <time> || <easing-function> || <time> ||
+// <single-animation-iteration-count> || <single-animation-direction> ||
+// <single-animation-fill-mode> || <single-animation-play-state> ||
+// [ none | <keyframes-name> ]
+test_computed_value("animation", "1s", "1s ease 0s 1 normal none running none");
+test_computed_value("animation", "cubic-bezier(0, -2, 1, 3)", "0s cubic-bezier(0, -2, 1, 3) 0s 1 normal none running none");
+test_computed_value("animation", "1s -3s", "1s ease -3s 1 normal none running none");
+test_computed_value("animation", "4", "0s ease 0s 4 normal none running none");
+test_computed_value("animation", "reverse", "0s ease 0s 1 reverse none running none");
+test_computed_value("animation", "both", "0s ease 0s 1 normal both running none");
+test_computed_value("animation", "paused", "0s ease 0s 1 normal none paused none");
+test_computed_value("animation", "none", "0s ease 0s 1 normal none running none");
+test_computed_value("animation", "anim", "0s ease 0s 1 normal none running anim");
+
+test_computed_value("animation", "anim paused both reverse 4 1s -3s cubic-bezier(0, -2, 1, 3)",
+  "1s cubic-bezier(0, -2, 1, 3) -3s 4 reverse both paused anim");
+
+test_computed_value("animation", "anim paused both reverse, 4 1s -3s cubic-bezier(0, -2, 1, 3)",
+  "0s ease 0s 1 reverse both paused anim, 1s cubic-bezier(0, -2, 1, 3) -3s 4 normal none running none");
+
+// TODO: Add test with a single timing-function keyword.
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-computed.html b/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-computed.html
new file mode 100644
index 0000000..3f253c3
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/css/css-transitions/parsing/transition-computed.html
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>CSS Transitions: getComputedStyle().transition</title>
+<link rel="help" href="https://drafts.csswg.org/css-transitions/#transition-shorthand-property">
+<meta name="assert" content="transition computed value is as specified.">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/css/support/computed-testcommon.js"></script>
+</head>
+<body>
+<div id="target"></div>
+<script>
+// <single-transition> = [ none | <single-transition-property> ] ||
+// <time> || <easing-function> || <time>
+test_computed_value("transition", "1s", "all 1s ease 0s");
+test_computed_value("transition", "cubic-bezier(0, -2, 1, 3)", "all 0s cubic-bezier(0, -2, 1, 3) 0s");
+test_computed_value("transition", "1s -3s", "all 1s ease -3s");
+test_computed_value("transition", "none", "none 0s ease 0s");
+test_computed_value("transition", "top", "top 0s ease 0s");
+
+test_computed_value("transition", "1s -3s cubic-bezier(0, -2, 1, 3) top", "top 1s cubic-bezier(0, -2, 1, 3) -3s");
+test_computed_value("transition", "1s -3s, cubic-bezier(0, -2, 1, 3) top", "all 1s ease -3s, top 0s cubic-bezier(0, -2, 1, 3) 0s");
+
+// TODO: Add test with a single timing-function keyword.
+</script>
+</body>
+</html>
diff --git a/third_party/blink/web_tests/external/wpt/domparsing/insert_adjacent_html-expected.txt b/third_party/blink/web_tests/external/wpt/domparsing/insert_adjacent_html-expected.txt
deleted file mode 100644
index df36e01..0000000
--- a/third_party/blink/web_tests/external/wpt/domparsing/insert_adjacent_html-expected.txt
+++ /dev/null
@@ -1,33 +0,0 @@
-This is a testharness.js-based test.
-PASS beforeBegin content without next sibling
-PASS Afterbegin content without next sibling
-PASS BeforeEnd content without next sibling
-PASS afterend content without next sibling
-PASS beforeBegin content again, with next sibling
-PASS Afterbegin content again, with next sibling
-PASS BeforeEnd content again, with next sibling
-PASS afterend content again, with next sibling
-PASS Should throw when inserting with invalid position string
-PASS When the parent node is null, insertAdjacentHTML should throw for beforebegin and afterend (text)
-PASS When the parent node is null, insertAdjacentHTML should throw for beforebegin and afterend (comments)
-PASS When the parent node is null, insertAdjacentHTML should throw for beforebegin and afterend (elements)
-PASS When the parent node is a document, insertAdjacentHTML should throw for beforebegin and afterend (text)
-PASS When the parent node is a document, insertAdjacentHTML should throw for beforebegin and afterend (comments)
-PASS When the parent node is a document, insertAdjacentHTML should throw for beforebegin and afterend (elements)
-PASS Inserting after being and before end should order things correctly
-PASS beforeBegin child node not in tree but has parent
-PASS Afterbegin child node not in tree but has parent
-PASS BeforeEnd child node not in tree but has parent
-PASS afterend child node not in tree but has parent
-PASS Should not run script when appending things which have descendant <script> inserted via insertAdjacentHTML
-PASS beforeBegin content2 without next sibling
-PASS Afterbegin content2 without next sibling
-PASS BeforeEnd content2 without next sibling
-PASS afterend content2 without next sibling
-PASS beforeBegin content2 test again, now that there's a next sibling
-PASS Afterbegin content2 test again, now that there's a next sibling
-PASS BeforeEnd content2 test again, now that there's a next sibling
-PASS afterend content2 test again, now that there's a next sibling
-FAIL Inserting kids of the <html> element should not do weird things with implied <body>/<head> tags assert_equals: Should still have one head expected 1 but got 3
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/fonts/Ahem.ttf.headers b/third_party/blink/web_tests/external/wpt/fonts/Ahem.ttf.headers
index cb762ef..659e376 100644
--- a/third_party/blink/web_tests/external/wpt/fonts/Ahem.ttf.headers
+++ b/third_party/blink/web_tests/external/wpt/fonts/Ahem.ttf.headers
@@ -1 +1,2 @@
 Access-Control-Allow-Origin: *
+Cache-Control: max-age=3600
diff --git a/third_party/blink/web_tests/external/wpt/fonts/CanvasTest.ttf.headers b/third_party/blink/web_tests/external/wpt/fonts/CanvasTest.ttf.headers
new file mode 100644
index 0000000..6f34caa
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fonts/CanvasTest.ttf.headers
@@ -0,0 +1 @@
+Cache-Control: max-age=3600
diff --git a/third_party/blink/web_tests/external/wpt/fonts/CanvasTest.ttf.sub.headers b/third_party/blink/web_tests/external/wpt/fonts/CanvasTest.ttf.sub.headers
deleted file mode 100644
index 360e668..0000000
--- a/third_party/blink/web_tests/external/wpt/fonts/CanvasTest.ttf.sub.headers
+++ /dev/null
@@ -1 +0,0 @@
-Cache-Control: max-age=1000
diff --git a/third_party/blink/web_tests/external/wpt/fonts/ahem.css.headers b/third_party/blink/web_tests/external/wpt/fonts/ahem.css.headers
new file mode 100644
index 0000000..e828b62
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fonts/ahem.css.headers
@@ -0,0 +1,2 @@
+Content-Type: text/css;charset=utf-8
+Cache-Control: max-age=3600
diff --git a/third_party/blink/web_tests/external/wpt/generic-sensor/resources/generic-sensor-helpers.js b/third_party/blink/web_tests/external/wpt/generic-sensor/resources/generic-sensor-helpers.js
index 8302f6f..afc2fad 100644
--- a/third_party/blink/web_tests/external/wpt/generic-sensor/resources/generic-sensor-helpers.js
+++ b/third_party/blink/web_tests/external/wpt/generic-sensor/resources/generic-sensor-helpers.js
@@ -61,8 +61,11 @@
 }
 
 function verifySensorReading(pattern, values, timestamp, isNull) {
+  // If |val| cannot be converted to a float, we return the original value.
+  // This can happen when a value in |pattern| is not a number.
   function round(val) {
-    return Number.parseFloat(val).toPrecision(6);
+    const res = Number.parseFloat(val).toPrecision(6);
+    return res === "NaN" ? val : res;
   }
 
   if (isNull) {
@@ -92,6 +95,10 @@
     accuracy, altitudeAccuracy, heading, speed], timestamp, isNull);
 }
 
+function verifyProximitySensorReading(pattern, {distance, max, near, timestamp}, isNull) {
+  return verifySensorReading(pattern, [distance, max, near], timestamp, isNull);
+}
+
 // A "sliding window" that iterates over |data| and returns one item at a
 // time, advancing and wrapping around as needed. |data| must be an array of
 // arrays.
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/encoding.idl b/third_party/blink/web_tests/external/wpt/interfaces/encoding.idl
index c89cad4..d4fffa89 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/encoding.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/encoding.idl
@@ -18,9 +18,10 @@
   boolean stream = false;
 };
 
-[Constructor(optional DOMString label = "utf-8", optional TextDecoderOptions options = {}),
- Exposed=(Window,Worker)]
+[Exposed=(Window,Worker)]
 interface TextDecoder {
+  constructor(optional DOMString label = "utf-8", optional TextDecoderOptions options = {});
+
   USVString decode(optional BufferSource input, optional TextDecodeOptions options = {});
 };
 TextDecoder includes TextDecoderCommon;
@@ -34,9 +35,10 @@
   unsigned long long written;
 };
 
-[Constructor,
- Exposed=(Window,Worker)]
+[Exposed=(Window,Worker)]
 interface TextEncoder {
+  constructor();
+
   [NewObject] Uint8Array encode(optional USVString input = "");
   TextEncoderEncodeIntoResult encodeInto(USVString source, Uint8Array destination);
 };
@@ -47,16 +49,16 @@
   readonly attribute WritableStream writable;
 };
 
-[Constructor(optional DOMString label = "utf-8", optional TextDecoderOptions options),
- Exposed=(Window,Worker)]
+[Exposed=(Window,Worker)]
 interface TextDecoderStream {
+  constructor(optional DOMString label = "utf-8", optional TextDecoderOptions options = {});
 };
 TextDecoderStream includes TextDecoderCommon;
 TextDecoderStream includes GenericTransformStream;
 
-[Constructor,
- Exposed=(Window,Worker)]
+[Exposed=(Window,Worker)]
 interface TextEncoderStream {
+  constructor();
 };
 TextEncoderStream includes TextEncoderCommon;
 TextEncoderStream includes GenericTransformStream;
diff --git a/third_party/blink/web_tests/external/wpt/interfaces/webrtc.idl b/third_party/blink/web_tests/external/wpt/interfaces/webrtc.idl
index f56ff80..b865738 100644
--- a/third_party/blink/web_tests/external/wpt/interfaces/webrtc.idl
+++ b/third_party/blink/web_tests/external/wpt/interfaces/webrtc.idl
@@ -91,19 +91,20 @@
   "connected"
 };
 
-[Exposed=Window, Constructor(optional RTCConfiguration configuration)]
-interface RTCPeerConnection : EventTarget {
-  Promise<RTCSessionDescriptionInit> createOffer(optional RTCOfferOptions options);
-  Promise<RTCSessionDescriptionInit> createAnswer(optional RTCAnswerOptions options);
-  Promise<void> setLocalDescription(optional RTCSessionDescriptionInit description);
+[Exposed=Window]
+interface RTCPeerConnection : EventTarget  {
+  constructor(optional RTCConfiguration configuration = {});
+  Promise<RTCSessionDescriptionInit> createOffer(optional RTCOfferOptions options = {});
+  Promise<RTCSessionDescriptionInit> createAnswer(optional RTCAnswerOptions options = {});
+  Promise<void> setLocalDescription(optional RTCSessionDescriptionInit description = {});
   readonly attribute RTCSessionDescription? localDescription;
   readonly attribute RTCSessionDescription? currentLocalDescription;
   readonly attribute RTCSessionDescription? pendingLocalDescription;
-  Promise<void> setRemoteDescription(optional RTCSessionDescriptionInit description);
+  Promise<void> setRemoteDescription(optional RTCSessionDescriptionInit description = {});
   readonly attribute RTCSessionDescription? remoteDescription;
   readonly attribute RTCSessionDescription? currentRemoteDescription;
   readonly attribute RTCSessionDescription? pendingRemoteDescription;
-  Promise<void> addIceCandidate(optional RTCIceCandidateInit candidate);
+  Promise<void> addIceCandidate(optional RTCIceCandidateInit candidate = {});
   readonly attribute RTCSignalingState signalingState;
   readonly attribute RTCIceGatheringState iceGatheringState;
   readonly attribute RTCIceConnectionState iceConnectionState;
@@ -121,18 +122,21 @@
   attribute EventHandler oniceconnectionstatechange;
   attribute EventHandler onicegatheringstatechange;
   attribute EventHandler onconnectionstatechange;
-};
 
-partial interface RTCPeerConnection {
+  // Legacy Interface Extensions
+  // Supporting the methods in this section is optional.
+  // If these methods are supported
+  // they must be implemented as defined
+  // in section "Legacy Interface Extensions"
   Promise<void> createOffer(RTCSessionDescriptionCallback successCallback,
                             RTCPeerConnectionErrorCallback failureCallback,
-                            optional RTCOfferOptions options);
-  Promise<void> setLocalDescription(optional RTCSessionDescriptionInit description,
+                            optional RTCOfferOptions options = {});
+  Promise<void> setLocalDescription(optional RTCSessionDescriptionInit description = {},
                                     VoidFunction successCallback,
                                     RTCPeerConnectionErrorCallback failureCallback);
   Promise<void> createAnswer(RTCSessionDescriptionCallback successCallback,
                              RTCPeerConnectionErrorCallback failureCallback);
-  Promise<void> setRemoteDescription(optional RTCSessionDescriptionInit description,
+  Promise<void> setRemoteDescription(optional RTCSessionDescriptionInit description = {},
                                      VoidFunction successCallback,
                                      RTCPeerConnectionErrorCallback failureCallback);
   Promise<void> addIceCandidate(RTCIceCandidateInit candidate,
@@ -156,8 +160,9 @@
   "rollback"
 };
 
-[Exposed=Window, Constructor(optional RTCSessionDescriptionInit descriptionInitDict)]
+[Exposed=Window]
 interface RTCSessionDescription {
+  constructor(optional RTCSessionDescriptionInit descriptionInitDict = {});
   readonly attribute RTCSdpType type;
   readonly attribute DOMString sdp;
   [Default] object toJSON();
@@ -168,8 +173,9 @@
   DOMString sdp = "";
 };
 
-[Exposed=Window, Constructor(optional RTCIceCandidateInit candidateInitDict)]
+[Exposed=Window]
 interface RTCIceCandidate {
+  constructor(optional RTCIceCandidateInit candidateInitDict = {});
   readonly attribute DOMString candidate;
   readonly attribute DOMString? sdpMid;
   readonly attribute unsigned short? sdpMLineIndex;
@@ -212,9 +218,9 @@
   "relay"
 };
 
-[Exposed=Window,
- Constructor(DOMString type, optional RTCPeerConnectionIceEventInit eventInitDict)]
+[Exposed=Window]
 interface RTCPeerConnectionIceEvent : Event {
+  constructor(DOMString type, optional RTCPeerConnectionIceEventInit eventInitDict = {});
   readonly attribute RTCIceCandidate? candidate;
   readonly attribute DOMString? url;
 };
@@ -224,9 +230,9 @@
   DOMString? url;
 };
 
-[Exposed=Window,
- Constructor(DOMString type, RTCPeerConnectionIceErrorEventInit eventInitDict)]
+[Exposed=Window]
 interface RTCPeerConnectionIceErrorEvent : Event {
+  constructor(DOMString type, RTCPeerConnectionIceErrorEventInit eventInitDict);
   readonly attribute DOMString hostCandidate;
   readonly attribute DOMString url;
   readonly attribute unsigned short errorCode;
@@ -248,7 +254,8 @@
 };
 
 partial interface RTCPeerConnection {
-  static Promise<RTCCertificate> generateCertificate(AlgorithmIdentifier keygenAlgorithm);
+  static Promise<RTCCertificate>
+      generateCertificate(AlgorithmIdentifier keygenAlgorithm);
 };
 
 dictionary RTCCertificateExpiration {
@@ -269,7 +276,7 @@
   RTCRtpSender addTrack(MediaStreamTrack track, MediaStream... streams);
   void removeTrack(RTCRtpSender sender);
   RTCRtpTransceiver addTransceiver((MediaStreamTrack or DOMString) trackOrKind,
-                                   optional RTCRtpTransceiverInit init);
+                                   optional RTCRtpTransceiverInit init = {});
   attribute EventHandler ontrack;
 };
 
@@ -488,8 +495,9 @@
   "rtcp"
 };
 
-[Exposed=Window, Constructor(DOMString type, RTCTrackEventInit eventInitDict)]
+[Exposed=Window]
 interface RTCTrackEvent : Event {
+  constructor(DOMString type, RTCTrackEventInit eventInitDict);
   readonly attribute RTCRtpReceiver receiver;
   readonly attribute MediaStreamTrack track;
   [SameObject] readonly attribute FrozenArray<MediaStream> streams;
@@ -506,7 +514,7 @@
 partial interface RTCPeerConnection {
   readonly attribute RTCSctpTransport? sctp;
   RTCDataChannel createDataChannel(USVString label,
-                                   optional RTCDataChannelInit dataChannelDict);
+                                   optional RTCDataChannelInit dataChannelDict = {});
   attribute EventHandler ondatachannel;
 };
 
@@ -569,8 +577,9 @@
   "closed"
 };
 
-[Exposed=Window, Constructor(DOMString type, RTCDataChannelEventInit eventInitDict)]
+[Exposed=Window]
 interface RTCDataChannelEvent : Event {
+  constructor(DOMString type, RTCDataChannelEventInit eventInitDict);
   readonly attribute RTCDataChannel channel;
 };
 
@@ -590,9 +599,9 @@
   readonly attribute DOMString toneBuffer;
 };
 
-[Exposed=Window,
- Constructor(DOMString type, RTCDTMFToneChangeEventInit eventInitDict)]
+[Exposed=Window]
 interface RTCDTMFToneChangeEvent : Event {
+  constructor(DOMString type, RTCDTMFToneChangeEventInit eventInitDict);
   readonly attribute DOMString tone;
 };
 
@@ -616,9 +625,9 @@
   required DOMString id;
 };
 
-[Exposed=Window,
- Constructor(DOMString type, RTCStatsEventInit eventInitDict)]
+[Exposed=Window]
 interface RTCStatsEvent : Event {
+  constructor(DOMString type, RTCStatsEventInit eventInitDict);
   readonly attribute RTCStatsReport report;
 };
 
@@ -626,8 +635,9 @@
   required RTCStatsReport report;
 };
 
-[Exposed=Window, Constructor(RTCErrorInit init, optional DOMString message = "")]
+[Exposed=Window]
 interface RTCError : DOMException {
+  constructor(RTCErrorInit init, optional DOMString message = "");
   readonly attribute RTCErrorDetailType errorDetail;
   readonly attribute long? sdpLineNumber;
   readonly attribute long? httpRequestStatusCode;
@@ -663,9 +673,9 @@
   "hardware-encoder-error"
 };
 
-[Exposed=Window,
- Constructor(DOMString type, RTCErrorEventInit eventInitDict)]
+[Exposed=Window]
 interface RTCErrorEvent : Event {
+  constructor(DOMString type, RTCErrorEventInit eventInitDict);
   [SameObject] readonly attribute RTCError error;
 };
 
diff --git a/third_party/blink/web_tests/external/wpt/resources/chromium/generic_sensor_mocks.js b/third_party/blink/web_tests/external/wpt/resources/chromium/generic_sensor_mocks.js
index 4f137023..a7272a6 100644
--- a/third_party/blink/web_tests/external/wpt/resources/chromium/generic_sensor_mocks.js
+++ b/third_party/blink/web_tests/external/wpt/resources/chromium/generic_sensor_mocks.js
@@ -150,7 +150,8 @@
         ['RelativeOrientationSensor',
             device.mojom.SensorType.RELATIVE_ORIENTATION_QUATERNION],
         ['RelativeOrientationEulerAngles',
-            device.mojom.SensorType.RELATIVE_ORIENTATION_EULER_ANGLES]
+            device.mojom.SensorType.RELATIVE_ORIENTATION_EULER_ANGLES],
+        ['ProximitySensor', device.mojom.SensorType.PROXIMITY]
       ]);
       this.binding_ = new mojo.Binding(device.mojom.SensorProvider, this);
 
diff --git a/third_party/blink/web_tests/external/wpt/webrtc-stats/idlharness.window-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc-stats/idlharness.window-expected.txt
deleted file mode 100644
index 1c7c1ea4..0000000
--- a/third_party/blink/web_tests/external/wpt/webrtc-stats/idlharness.window-expected.txt
+++ /dev/null
@@ -1,45 +0,0 @@
-This is a testharness.js-based test.
-PASS idl_test setup
-FAIL idl_test validation Validation error at line 127 in webrtc, inside `partial interface RTCPeerConnection`:
-  Promise<void> createOffer(RTCSessionDescriptionCallback successCallback,
-                ^ The operation "createOffer" has already been defined for the base interface "RTCPeerConnection" either in itself or in a mixin
-
-Validation error at line 130 in webrtc, inside `partial interface RTCPeerConnection`:
-  Promise<void> setLocalDescription(optional RTCSessionDescriptionInit description
-                ^ The operation "setLocalDescription" has already been defined for the base interface "RTCPeerConnection" either in itself or in a mixin
-
-Validation error at line 133 in webrtc, inside `partial interface RTCPeerConnection`:
-  Promise<void> createAnswer(RTCSessionDescriptionCallback successCallback,
-                ^ The operation "createAnswer" has already been defined for the base interface "RTCPeerConnection" either in itself or in a mixin
-
-Validation error at line 135 in webrtc, inside `partial interface RTCPeerConnection`:
-  Promise<void> setRemoteDescription(optional RTCSessionDescriptionInit description
-                ^ The operation "setRemoteDescription" has already been defined for the base interface "RTCPeerConnection" either in itself or in a mixin
-
-Validation error at line 138 in webrtc, inside `partial interface RTCPeerConnection`:
-  Promise<void> addIceCandidate(RTCIceCandidateInit candidate,
-                ^ The operation "addIceCandidate" has already been defined for the base interface "RTCPeerConnection" either in itself or in a mixin
-PASS Partial dictionary RTCCodecStats: original dictionary defined
-PASS Partial dictionary RTCCodecStats: member names are unique
-PASS Partial dictionary RTCIceCandidateStats: original dictionary defined
-PASS Partial dictionary RTCIceCandidateStats: member names are unique
-PASS Partial dictionary RTCIceCandidatePairStats: original dictionary defined
-PASS Partial dictionary RTCIceCandidatePairStats: member names are unique
-PASS Partial dictionary RTCRtpStreamStats: original dictionary defined
-PASS Partial dictionary RTCRtpStreamStats: member names are unique
-PASS Partial dictionary RTCInboundRtpStreamStats: original dictionary defined
-PASS Partial dictionary RTCInboundRtpStreamStats: member names are unique
-PASS Partial dictionary RTCAudioHandlerStats: original dictionary defined
-PASS Partial dictionary RTCAudioHandlerStats: member names are unique
-PASS Partial dictionary RTCAudioSenderStats: original dictionary defined
-PASS Partial dictionary RTCAudioSenderStats: member names are unique
-PASS Partial dictionary RTCAudioReceiverStats: original dictionary defined
-PASS Partial dictionary RTCAudioReceiverStats: member names are unique
-PASS Partial dictionary RTCVideoHandlerStats: original dictionary defined
-PASS Partial dictionary RTCVideoHandlerStats: member names are unique
-PASS Partial dictionary RTCVideoSenderStats: original dictionary defined
-PASS Partial dictionary RTCVideoSenderStats: member names are unique
-PASS Partial dictionary RTCVideoReceiverStats: original dictionary defined
-PASS Partial dictionary RTCVideoReceiverStats: member names are unique
-Harness: the test ran to completion.
-
diff --git a/third_party/blink/web_tests/external/wpt/webrtc/idlharness.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/webrtc/idlharness.https.window-expected.txt
index 1049e1a..4a3962de 100644
--- a/third_party/blink/web_tests/external/wpt/webrtc/idlharness.https.window-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webrtc/idlharness.https.window-expected.txt
@@ -1,42 +1,22 @@
 This is a testharness.js-based test.
-Found 516 tests; 476 PASS, 40 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 514 tests; 475 PASS, 39 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
-FAIL idl_test validation Validation error at line 127 in webrtc, inside `partial interface RTCPeerConnection`:
-  Promise<void> createOffer(RTCSessionDescriptionCallback successCallback,
-                ^ The operation "createOffer" has already been defined for the base interface "RTCPeerConnection" either in itself or in a mixin
-
-Validation error at line 130 in webrtc, inside `partial interface RTCPeerConnection`:
-  Promise<void> setLocalDescription(optional RTCSessionDescriptionInit description
-                ^ The operation "setLocalDescription" has already been defined for the base interface "RTCPeerConnection" either in itself or in a mixin
-
-Validation error at line 133 in webrtc, inside `partial interface RTCPeerConnection`:
-  Promise<void> createAnswer(RTCSessionDescriptionCallback successCallback,
-                ^ The operation "createAnswer" has already been defined for the base interface "RTCPeerConnection" either in itself or in a mixin
-
-Validation error at line 135 in webrtc, inside `partial interface RTCPeerConnection`:
-  Promise<void> setRemoteDescription(optional RTCSessionDescriptionInit description
-                ^ The operation "setRemoteDescription" has already been defined for the base interface "RTCPeerConnection" either in itself or in a mixin
-
-Validation error at line 138 in webrtc, inside `partial interface RTCPeerConnection`:
-  Promise<void> addIceCandidate(RTCIceCandidateInit candidate,
-                ^ The operation "addIceCandidate" has already been defined for the base interface "RTCPeerConnection" either in itself or in a mixin
+PASS idl_test validation
 PASS Test driver for asyncInitCertificate
 PASS Test driver for asyncInitTransports
 PASS Test driver for asyncInitMediaStreamTrack
-PASS Partial interface RTCPeerConnection: original interface defined
-PASS Partial interface RTCPeerConnection: member names are unique
 PASS Partial dictionary RTCOfferOptions: original dictionary defined
 PASS Partial dictionary RTCOfferOptions: member names are unique
+PASS Partial interface RTCPeerConnection: original interface defined
+PASS Partial interface RTCPeerConnection: member names are unique
 PASS Partial interface RTCPeerConnection[2]: original interface defined
 PASS Partial interface RTCPeerConnection[2]: member names are unique
 PASS Partial interface RTCPeerConnection[3]: original interface defined
 PASS Partial interface RTCPeerConnection[3]: member names are unique
-PASS Partial interface RTCPeerConnection[4]: original interface defined
-PASS Partial interface RTCPeerConnection[4]: member names are unique
 PASS Partial interface RTCRtpSender: original interface defined
 PASS Partial interface RTCRtpSender: member names are unique
-PASS Partial interface RTCPeerConnection[5]: original interface defined
-PASS Partial interface RTCPeerConnection[5]: member names are unique
+PASS Partial interface RTCPeerConnection[4]: original interface defined
+PASS Partial interface RTCPeerConnection[4]: member names are unique
 PASS RTCPeerConnection interface: existence and properties of interface object
 PASS RTCPeerConnection interface object length
 PASS RTCPeerConnection interface object name
diff --git a/third_party/blink/web_tests/external/wpt/webxr/idlharness.https.window-expected.txt b/third_party/blink/web_tests/external/wpt/webxr/idlharness.https.window-expected.txt
index 1d166e26..13bd434 100644
--- a/third_party/blink/web_tests/external/wpt/webxr/idlharness.https.window-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/webxr/idlharness.https.window-expected.txt
@@ -1,5 +1,5 @@
 This is a testharness.js-based test.
-Found 204 tests; 199 PASS, 5 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 204 tests; 202 PASS, 2 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
 PASS idl_test validation
 PASS Partial interface Navigator: original interface defined
@@ -24,13 +24,13 @@
 PASS XR interface: existence and properties of interface prototype object
 PASS XR interface: existence and properties of interface prototype object's "constructor" property
 PASS XR interface: existence and properties of interface prototype object's @@unscopables property
-FAIL XR interface: operation isSessionSupported(XRSessionMode) assert_own_property: interface prototype object missing non-static operation expected property "isSessionSupported" missing
+PASS XR interface: operation isSessionSupported(XRSessionMode)
 PASS XR interface: operation requestSession(XRSessionMode, XRSessionInit)
 PASS XR interface: attribute ondevicechange
 PASS XR must be primary interface of navigator.xr
 PASS Stringification of navigator.xr
-FAIL XR interface: navigator.xr must inherit property "isSessionSupported(XRSessionMode)" with the proper type assert_inherits: property "isSessionSupported" not found in prototype chain
-FAIL XR interface: calling isSessionSupported(XRSessionMode) on navigator.xr with too few arguments must throw TypeError assert_inherits: property "isSessionSupported" not found in prototype chain
+PASS XR interface: navigator.xr must inherit property "isSessionSupported(XRSessionMode)" with the proper type
+PASS XR interface: calling isSessionSupported(XRSessionMode) on navigator.xr with too few arguments must throw TypeError
 PASS XR interface: navigator.xr must inherit property "requestSession(XRSessionMode, XRSessionInit)" with the proper type
 PASS XR interface: calling requestSession(XRSessionMode, XRSessionInit) on navigator.xr with too few arguments must throw TypeError
 PASS XR interface: navigator.xr must inherit property "ondevicechange" with the proper type
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrDevice_isSessionSupported_immersive.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrDevice_isSessionSupported_immersive.https.html
new file mode 100644
index 0000000..2f1129f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webxr/xrDevice_isSessionSupported_immersive.https.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<body>
+  <script src=/resources/testharness.js></script>
+  <script src=/resources/testharnessreport.js></script>
+  <script src="resources/webxr_util.js"></script>
+  <script src="resources/webxr_test_constants.js"></script>
+  <script>
+    xr_promise_test(
+      "isSessionSupported resolves to true when immersive options supported",
+      (t) => {
+        return navigator.xr.test.simulateDeviceConnection(TRACKED_IMMERSIVE_DEVICE)
+          .then( (controller) => {
+            return navigator.xr.isSessionSupported('immersive-vr').then((supported) => {
+              t.step(() => {
+                assert_true(supported);
+              });
+            });
+          });
+      });
+  </script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrDevice_isSessionSupported_immersive_unsupported.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrDevice_isSessionSupported_immersive_unsupported.https.html
new file mode 100644
index 0000000..41ae338
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webxr/xrDevice_isSessionSupported_immersive_unsupported.https.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<body>
+  <script src=/resources/testharness.js></script>
+  <script src=/resources/testharnessreport.js></script>
+  <script src="resources/webxr_util.js"></script>
+  <script src="resources/webxr_test_constants.js"></script>
+  <script>
+    xr_promise_test(
+      "isSessionSupported resolves to false when options not supported",
+      (t) => {
+      return navigator.xr.test.simulateDeviceConnection(VALID_NON_IMMERSIVE_DEVICE)
+        .then( (controller) => {
+          return navigator.xr.isSessionSupported('immersive-vr').then((supported) => {
+            t.step(() => {
+              assert_false(supported);
+            });
+          });
+        });
+    });
+  </script>
+</body>
diff --git a/third_party/blink/web_tests/external/wpt/webxr/xrDevice_isSessionSupported_inline.https.html b/third_party/blink/web_tests/external/wpt/webxr/xrDevice_isSessionSupported_inline.https.html
new file mode 100644
index 0000000..bf8d14a8
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/webxr/xrDevice_isSessionSupported_inline.https.html
@@ -0,0 +1,22 @@
+<!DOCTYPE html>
+<body>
+  <script src=/resources/testharness.js></script>
+  <script src=/resources/testharnessreport.js></script>
+  <script src="resources/webxr_util.js"></script>
+  <script src="resources/webxr_test_constants.js"></script>
+  <script>
+    xr_promise_test(
+      "isSessionSupported resolves to true when inline options supported",
+      (t) => {
+      return navigator.xr.test.simulateDeviceConnection(TRACKED_IMMERSIVE_DEVICE)
+        .then( (controller) => {
+          // Inline sessions should be supported.
+          return navigator.xr.isSessionSupported('inline').then((supported) => {
+            t.step(() => {
+              assert_true(supported);
+            });
+          });
+        });
+    });
+  </script>
+</body>
diff --git a/third_party/blink/web_tests/fast/canvas/canvas-filter-frameless-document-late-append-expected.txt b/third_party/blink/web_tests/fast/canvas/canvas-filter-frameless-document-late-append-expected.txt
new file mode 100644
index 0000000..d3516960
--- /dev/null
+++ b/third_party/blink/web_tests/fast/canvas/canvas-filter-frameless-document-late-append-expected.txt
@@ -0,0 +1 @@
+ This test passes if it doesn't crash.
diff --git a/third_party/blink/web_tests/fast/canvas/canvas-filter-frameless-document-late-append.html b/third_party/blink/web_tests/fast/canvas/canvas-filter-frameless-document-late-append.html
new file mode 100644
index 0000000..136e2bf
--- /dev/null
+++ b/third_party/blink/web_tests/fast/canvas/canvas-filter-frameless-document-late-append.html
@@ -0,0 +1,13 @@
+<body>
+  <script>
+    if (window.testRunner)
+      testRunner.dumpAsText();
+    var doc = new Document();
+    var canvas = doc.createElementNS('http://www.w3.org/1999/xhtml', 'canvas')
+    var ctx = canvas.getContext('2d')
+    ctx.filter = 'blur(1ch)'
+    document.body.appendChild(canvas)
+    ctx.strokeRect(75, 140, 150, 110)
+  </script>
+  This test passes if it doesn't crash.
+</body>
\ No newline at end of file
diff --git a/third_party/blink/web_tests/fast/dom/insertAdjacentHTML-DocumentFragment-crash-expected.txt b/third_party/blink/web_tests/fast/dom/insertAdjacentHTML-DocumentFragment-crash-expected.txt
index d19ecd869..e7a5bb4e3 100644
--- a/third_party/blink/web_tests/fast/dom/insertAdjacentHTML-DocumentFragment-crash-expected.txt
+++ b/third_party/blink/web_tests/fast/dom/insertAdjacentHTML-DocumentFragment-crash-expected.txt
@@ -1,2 +1 @@
-CONSOLE ERROR: line 9: Uncaught NoModificationAllowedError: Failed to execute 'insertAdjacentHTML' on 'Element': The element has no parent.
 This test passes if it doesn't crash (or ASSERT).
diff --git a/third_party/blink/web_tests/fast/workers/worker-performance-time.html b/third_party/blink/web_tests/fast/workers/worker-performance-time.html
index 7bea03f..c57841b 100644
--- a/third_party/blink/web_tests/fast/workers/worker-performance-time.html
+++ b/third_party/blink/web_tests/fast/workers/worker-performance-time.html
@@ -7,7 +7,7 @@
 function animate(time) {
   var timeNow = performance.now();
   countWorker--;
-  self.postMessage([time,timeNow, countWorker]);
+  self.postMessage([time, timeNow, countWorker]);
   if(countWorker > 0)
     requestAnimationFrame(animate);
 };
@@ -18,16 +18,21 @@
 </script>
 <script>
 async_test(function(t) {
-  var blob = new Blob([document.getElementById("worker").textContent]);
-  var worker = new Worker(URL.createObjectURL(blob));
+  const blob = new Blob([document.getElementById("worker").textContent]);
+  const worker = new Worker(URL.createObjectURL(blob));
+  let delta = 0;
   worker.onmessage = t.step_func(function(pairTime) {
-    var time = pairTime.data[0];
-    var timeNow = pairTime.data[1];
-    var count = pairTime.data[2];
-    assert_approx_equals(time, timeNow, 1000, "Times must be close enough");
+    const time = pairTime.data[0];
+    const timeNow = pairTime.data[1];
+    const count = pairTime.data[2];
+    if (count == 9) {
+      delta = time - timeNow;
+    }
+    console.log(time, timeNow, count, delta);
+    assert_approx_equals(time, timeNow + delta, 1000, "Times must be close enough");
     if(count == 0)
       t.done();
   });
   worker.postMessage("");
 }, 'Test the timing in the worker to be consistent between animation and performance.now');
-</script>
\ No newline at end of file
+</script>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/intercept-css-enable-fetch-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/intercept-css-enable-fetch-expected.txt
index 0eeb08dd..d153fdd 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/intercept-css-enable-fetch-expected.txt
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/intercept-css-enable-fetch-expected.txt
@@ -5,13 +5,8 @@
 <html>
 <head>
 <title>webpage for repeat-fetch-service-worker.js</title>
-<script>
-function installSW() {
-  navigator.serviceWorker.register('repeat-fetch-service-worker.js');
-}
-</script>
 </head>
-<body onload="installSW()"><p>injected by service worker</p></body>
+<body><p>injected by service worker</p></body>
 </html>
 
 
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/intercept-css-enable-fetch.js b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/intercept-css-enable-fetch.js
index 3f8df3ea..cbd69055 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/intercept-css-enable-fetch.js
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/intercept-css-enable-fetch.js
@@ -2,25 +2,21 @@
   var {page, session, dp} = await testRunner.startURL(
       'resources/repeat-fetch-service-worker.html',
       'Verifies that service workers do not throw errors from devtools css enable initiated fetch.');
+  const swHelper = (await testRunner.loadScript('resources/service-worker-helper.js'))(dp, session);
 
   dp.ServiceWorker.onWorkerErrorReported(error => {
     testRunner.log(
-        'serivce worker reported error: ' + JSON.stringify(error, null, 2));
+        'service worker reported error: ' + JSON.stringify(error, null, 2));
     testRunner.completeTest();
   });
 
   await dp.Runtime.enable();
   await dp.ServiceWorker.enable();
 
-  let versions;
-  do {
-    const result = await dp.ServiceWorker.onceWorkerVersionUpdated();
-    versions = result.params.versions;
-  } while (!versions.length || versions[0].status !== 'activated');
-  await versions[0].registrationId;
-
+  await swHelper.installSWAndWaitForActivated('/inspector-protocol/service-worker/resources/repeat-fetch-service-worker.js');
   await dp.Page.enable();
   await dp.Page.reload();
+  await swHelper.installSWAndWaitForActivated('/inspector-protocol/service-worker/resources/repeat-fetch-service-worker.js');
 
   await dp.DOM.enable();
   await dp.CSS.enable();
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/network-extrainfo-main-request-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/network-extrainfo-main-request-expected.txt
new file mode 100644
index 0000000..17bedfc
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/network-extrainfo-main-request-expected.txt
@@ -0,0 +1,4 @@
+Verifies that requests made for service worker main scripts get Network.*ExtraInfo events for them.
+requestWillBeSent url: http://127.0.0.1:8000/inspector-protocol/service-worker/resources/repeat-fetch-service-worker.js
+requestIds match: true
+
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/network-extrainfo-main-request.js b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/network-extrainfo-main-request.js
new file mode 100644
index 0000000..1fd20422
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/network-extrainfo-main-request.js
@@ -0,0 +1,37 @@
+(async function(testRunner) {
+  var {page, session, dp} = await testRunner.startBlank(
+      'Verifies that requests made for service worker main scripts get Network.*ExtraInfo events for them.');
+  const swHelper = (await testRunner.loadScript('resources/service-worker-helper.js'))(dp, session);
+
+  await dp.Target.setAutoAttach(
+    {autoAttach: true, waitForDebuggerOnStart: true, flatten: true});
+
+  await session.navigate('resources/repeat-fetch-service-worker.html');
+
+  swHelper.installSWAndWaitForActivated('/inspector-protocol/service-worker/resources/repeat-fetch-service-worker.js');
+  const attachedToTarget = await dp.Target.onceAttachedToTarget();
+
+  const swdp = session.createChild(attachedToTarget.params.sessionId).protocol;
+  await swdp.Network.enable();
+
+  swdp.Runtime.runIfWaitingForDebugger();
+
+  const [
+    requestWillBeSent,
+    requestWillBeSentExtraInfo,
+    responseReceived,
+    responseReceivedExtraInfo
+  ] = await Promise.all([
+      swdp.Network.onceRequestWillBeSent(),
+      swdp.Network.onceRequestWillBeSentExtraInfo(),
+      swdp.Network.onceResponseReceived(),
+      swdp.Network.onceResponseReceivedExtraInfo()
+  ]);
+
+  const idsMatch = requestWillBeSent.params.requestId === requestWillBeSentExtraInfo.params.requestId
+    && requestWillBeSent.params.requestId === responseReceived.params.requestId
+    && requestWillBeSent.params.requestId === responseReceivedExtraInfo.params.requestId;
+  testRunner.log('requestWillBeSent url: ' + requestWillBeSent.params.request.url);
+  testRunner.log('requestIds match: ' + idsMatch);
+  testRunner.completeTest();
+});
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/network-extrainfo-subresource-expected.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/network-extrainfo-subresource-expected.txt
new file mode 100644
index 0000000..f51d33d1
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/network-extrainfo-subresource-expected.txt
@@ -0,0 +1,4 @@
+Verifies that subresource requests made by service workers get Network.*ExtraInfo events for them.
+requestWillBeSent url: http://127.0.0.1:8000/inspector-protocol/service-worker/resources/hello-world.txt
+requestIds match: true
+
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/network-extrainfo-subresource.js b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/network-extrainfo-subresource.js
new file mode 100644
index 0000000..00d8772
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/network-extrainfo-subresource.js
@@ -0,0 +1,41 @@
+(async function(testRunner) {
+  var {page, session, dp} = await testRunner.startBlank(
+      'Verifies that subresource requests made by service workers get Network.*ExtraInfo events for them.');
+  const swHelper = (await testRunner.loadScript('resources/service-worker-helper.js'))(dp, session);
+
+  let swdp = null;
+  await dp.Target.setAutoAttach(
+    {autoAttach: true, waitForDebuggerOnStart: false, flatten: true});
+  dp.Target.onAttachedToTarget(async event => {
+    swdp = session.createChild(event.params.sessionId).protocol;
+  });
+
+  await session.navigate('resources/repeat-fetch-service-worker.html');
+  await swHelper.installSWAndWaitForActivated('/inspector-protocol/service-worker/resources/repeat-fetch-service-worker.js');
+
+  await dp.Page.enable();
+  await dp.Page.reload();
+  await swHelper.installSWAndWaitForActivated('/inspector-protocol/service-worker/resources/repeat-fetch-service-worker.js');
+  await swdp.Network.enable();
+
+  const [
+    requestWillBeSent,
+    requestWillBeSentExtraInfo,
+    responseReceived,
+    responseReceivedExtraInfo,
+    evaluate
+  ] = await Promise.all([
+      swdp.Network.onceRequestWillBeSent(),
+      swdp.Network.onceRequestWillBeSentExtraInfo(),
+      swdp.Network.onceResponseReceived(),
+      swdp.Network.onceResponseReceivedExtraInfo(),
+      session.evaluate(`fetch('${testRunner.url('./resources/hello-world.txt')}')`)
+  ]);
+
+  const idsMatch = requestWillBeSent.params.requestId === requestWillBeSentExtraInfo.params.requestId
+    && requestWillBeSent.params.requestId === responseReceived.params.requestId
+    && requestWillBeSent.params.requestId === responseReceivedExtraInfo.params.requestId;
+  testRunner.log('requestWillBeSent url: ' + requestWillBeSent.params.request.url);
+  testRunner.log('requestIds match: ' + idsMatch);
+  testRunner.completeTest();
+});
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/resources/hello-world.txt b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/resources/hello-world.txt
new file mode 100644
index 0000000..3b18e51
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/resources/hello-world.txt
@@ -0,0 +1 @@
+hello world
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/resources/repeat-fetch-service-worker.html b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/resources/repeat-fetch-service-worker.html
index d3dbd5ff..2b51e73 100644
--- a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/resources/repeat-fetch-service-worker.html
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/resources/repeat-fetch-service-worker.html
@@ -2,11 +2,6 @@
 <html>
 <head>
 <title>webpage for repeat-fetch-service-worker.js</title>
-<script>
-function installSW() {
-  navigator.serviceWorker.register('repeat-fetch-service-worker.js');
-}
-</script>
 </head>
-<body onload="installSW()"></body>
+<body></body>
 </html>
diff --git a/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/resources/service-worker-helper.js b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/resources/service-worker-helper.js
new file mode 100644
index 0000000..9c599d2
--- /dev/null
+++ b/third_party/blink/web_tests/http/tests/inspector-protocol/service-worker/resources/service-worker-helper.js
@@ -0,0 +1,28 @@
+(function() {
+  class ServiceWorkerHelper {
+    constructor(dp, session) {
+      this._dp = dp;
+      this._session = session;
+    }
+
+    async installSWAndWaitForActivated(swUrl) {
+      await this._session.evaluateAsync(`
+        (async function() {
+          const reg = await navigator.serviceWorker.register('${swUrl}');
+          const worker = reg.installing || reg.waiting || reg.active;
+          if (worker.state === 'activated')
+            return;
+          return new Promise(resolve => {
+            worker.addEventListener('statechange', () => {
+              if (worker.state === 'activated')
+                resolve();
+            });
+          });
+        })()`);
+    }
+  };
+
+  return (dp, session) => {
+    return new ServiceWorkerHelper(dp, session);
+  };
+})()
diff --git a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/idlharness.https.window-expected.txt b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/idlharness.https.window-expected.txt
index a5334a6..5e43679 100644
--- a/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/idlharness.https.window-expected.txt
+++ b/third_party/blink/web_tests/virtual/webrtc-wpt-plan-b/external/wpt/webrtc/idlharness.https.window-expected.txt
@@ -1,42 +1,22 @@
 This is a testharness.js-based test.
-Found 516 tests; 407 PASS, 109 FAIL, 0 TIMEOUT, 0 NOTRUN.
+Found 514 tests; 406 PASS, 108 FAIL, 0 TIMEOUT, 0 NOTRUN.
 PASS idl_test setup
-FAIL idl_test validation Validation error at line 127 in webrtc, inside `partial interface RTCPeerConnection`:
-  Promise<void> createOffer(RTCSessionDescriptionCallback successCallback,
-                ^ The operation "createOffer" has already been defined for the base interface "RTCPeerConnection" either in itself or in a mixin
-
-Validation error at line 130 in webrtc, inside `partial interface RTCPeerConnection`:
-  Promise<void> setLocalDescription(optional RTCSessionDescriptionInit description
-                ^ The operation "setLocalDescription" has already been defined for the base interface "RTCPeerConnection" either in itself or in a mixin
-
-Validation error at line 133 in webrtc, inside `partial interface RTCPeerConnection`:
-  Promise<void> createAnswer(RTCSessionDescriptionCallback successCallback,
-                ^ The operation "createAnswer" has already been defined for the base interface "RTCPeerConnection" either in itself or in a mixin
-
-Validation error at line 135 in webrtc, inside `partial interface RTCPeerConnection`:
-  Promise<void> setRemoteDescription(optional RTCSessionDescriptionInit description
-                ^ The operation "setRemoteDescription" has already been defined for the base interface "RTCPeerConnection" either in itself or in a mixin
-
-Validation error at line 138 in webrtc, inside `partial interface RTCPeerConnection`:
-  Promise<void> addIceCandidate(RTCIceCandidateInit candidate,
-                ^ The operation "addIceCandidate" has already been defined for the base interface "RTCPeerConnection" either in itself or in a mixin
+PASS idl_test validation
 PASS Test driver for asyncInitCertificate
 FAIL Test driver for asyncInitTransports assert_unreached: Failed to run asyncInitTransports: Error: assert_true: Expect pc.sctp to be instance of RTCSctpTransport expected true got false Reached unreachable code
 PASS Test driver for asyncInitMediaStreamTrack
-PASS Partial interface RTCPeerConnection: original interface defined
-PASS Partial interface RTCPeerConnection: member names are unique
 PASS Partial dictionary RTCOfferOptions: original dictionary defined
 PASS Partial dictionary RTCOfferOptions: member names are unique
+PASS Partial interface RTCPeerConnection: original interface defined
+PASS Partial interface RTCPeerConnection: member names are unique
 PASS Partial interface RTCPeerConnection[2]: original interface defined
 PASS Partial interface RTCPeerConnection[2]: member names are unique
 PASS Partial interface RTCPeerConnection[3]: original interface defined
 PASS Partial interface RTCPeerConnection[3]: member names are unique
-PASS Partial interface RTCPeerConnection[4]: original interface defined
-PASS Partial interface RTCPeerConnection[4]: member names are unique
 PASS Partial interface RTCRtpSender: original interface defined
 PASS Partial interface RTCRtpSender: member names are unique
-PASS Partial interface RTCPeerConnection[5]: original interface defined
-PASS Partial interface RTCPeerConnection[5]: member names are unique
+PASS Partial interface RTCPeerConnection[4]: original interface defined
+PASS Partial interface RTCPeerConnection[4]: member names are unique
 PASS RTCPeerConnection interface: existence and properties of interface object
 PASS RTCPeerConnection interface object length
 PASS RTCPeerConnection interface object name
diff --git a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
index 3ddd88a8..07098809 100644
--- a/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/blink/web_tests/webexposed/global-interface-listing-expected.txt
@@ -10899,6 +10899,7 @@
     attribute @@toStringTag
     getter ondevicechange
     method constructor
+    method isSessionSupported
     method requestSession
     method supportsSession
     setter ondevicechange
diff --git a/third_party/feed/OWNERS b/third_party/feed/OWNERS
index 74086c2..0cce6ad 100644
--- a/third_party/feed/OWNERS
+++ b/third_party/feed/OWNERS
@@ -1,7 +1,7 @@
+carlosk@chromium.org
 fgorski@chromium.org
-pavely@chromium.org
+harringtond@chromium.org
 skym@chromium.org
-zea@chromium.org
 
-# Team: chrome-jardin-team@google.com
+# Team: feed@chromium.org
 # COMPONENT: UI>Browser>ContentSuggestions>Feed
diff --git a/third_party/feed/README.chromium b/third_party/feed/README.chromium
index b14e6b2..be83b36 100644
--- a/third_party/feed/README.chromium
+++ b/third_party/feed/README.chromium
@@ -2,7 +2,7 @@
 Short name: feed
 URL: https://chromium.googlesource.com/feed
 Version: 0
-Revision: c25c8f41145ed610d1a73004e8bcd62d8e8111c1
+Revision: 78a886b204af52d24e298852587fc99f68cee626
 License: Apache 2.0
 License File: LICENSE
 Security Critical: yes
diff --git a/tools/android/elf_compression/README.md b/tools/android/elf_compression/README.md
index 9d41fd94..660dcf3 100644
--- a/tools/android/elf_compression/README.md
+++ b/tools/android/elf_compression/README.md
@@ -3,8 +3,8 @@
 This directory contains the shared library compression tool that allows to
 reduce the shared library size by compressing non-performance critical code.
 The decompression is done on demand by a watcher thread that is set in a
-library constructor. This constructor (being a single .c file) should be
-included in the library build to be applied to it.
+library constructor. This constructor (located in a single .c file) should be
+included in the library's build.
 
 Additional information may be found in the tracking bug:
 https://crbug.com/998082
@@ -12,21 +12,22 @@
 The tool consists of 2 parts:
 ### Compression script
 This script does the compression part. It removes the specified range from
-the file and adds compressed version of it instead. It then sets library
-constructor's symbols to point at the cutted range and to the compressed
+the file and adds compressed version of it instead. It then sets decompression
+hook's smagic bytes to point at the cutted range and to the compressed
 version.
-### Library constructor
-Located at `constructor/` path and should be build together with the target
+### Decompression hook
+Located at `decompression_hook/` path and should be build together with the target
 library.
 
 It decompresses data from compressed section, provided by compression script
-and populates the target range.
+and populates the target range by setting a new library constructor which
+starts a watcher thread, handling page fault events.
 
 ## Usage
-Firstly, the library needs to be build with the tool's constructor. To do this
-add the following file to your build:
+Firstly, the library needs to be build with the tool's decompression hook. To
+do this add the following file to your build:
 
-    constructor/library_constructor.c
+    decompression_hook/decompression_hook.c
 
 Additionally the library must be linked with `-pthread` option.
 
diff --git a/tools/android/elf_compression/compress_section.py b/tools/android/elf_compression/compress_section.py
index 64d39e4..fb15c25 100755
--- a/tools/android/elf_compression/compress_section.py
+++ b/tools/android/elf_compression/compress_section.py
@@ -4,9 +4,9 @@
 # found in the LICENSE file.
 """This script compresses a part of shared library without breaking it.
 
-It compresses the specified file range which will be used by a new library
-constructor that uses userfaultfd to intercept access attempts to the range
-and decompress its data on demand.
+It compresses the specified file range which will be used by a library's
+decompression hook that uses userfaultfd to intercept access attempts to the
+range and decompress its data on demand.
 
 Technically this script does the following steps:
   1) Makes a copy of specified range, compresses it and adds it to the binary
@@ -20,8 +20,8 @@
     process.
   6) Changes cut range LOAD segment by zeroing the file_sz and setting
     mem_sz to the original range size, essentially lazily zeroing the space.
-  7) Changes address of the symbols provided by the library constructor to
-    point to the cut range and compressed section.
+  7) Changes magic bytes provided by the decompression hook to contain
+   addresses of cut range and compressed range.
 """
 
 import argparse
diff --git a/tools/android/elf_compression/constructor/library_constructor.c b/tools/android/elf_compression/decompression_hook/decompression_hook.c
similarity index 94%
rename from tools/android/elf_compression/constructor/library_constructor.c
rename to tools/android/elf_compression/decompression_hook/decompression_hook.c
index c808131..2077227 100644
--- a/tools/android/elf_compression/constructor/library_constructor.c
+++ b/tools/android/elf_compression/decompression_hook/decompression_hook.c
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-// This file contains userfaultfd watcher constructor which decompress
+// This file contains userfaultfd watcher constructor that decompress
 // parts of the library's code, compressed by compress_section.py script.
 #include <asm-generic/ioctls.h>
 #include <asm/unistd_64.h>
@@ -30,11 +30,6 @@
 
 // This function can be used to prevent a value or expression from being
 // optimized away by the compiler.
-//
-// This method is clang specific, hence the #error
-#ifndef __clang__
-#error "DoNotOptimize is clang specific method"
-#endif
 void DoNotOptimize(void* value) {
   __asm__ volatile("" : : "r,m"(value) : "memory");
 }
@@ -42,8 +37,11 @@
 // The following 4 arrays are here to be patched into by compress_section.py
 // script. They currently contain magic bytes that will be used to locate them
 // in the library file. DoNotOptimize method is applied to them at the
-// beginning of the constructor to ensure that the arrays are not optimized
-// away.
+// beginning of the decompression hook to ensure that the arrays are not
+// optimized away.
+//
+// TODO(https://crbug.com/998082): Check if dl_iterate_phdr can replace the
+// magic bytes approach.
 unsigned char g_dummy_cut_range_begin[8] = {0x2e, 0x2a, 0xee, 0xf6,
                                             0x45, 0x03, 0xd2, 0x50};
 unsigned char g_dummy_cut_range_end[8] = {0x52, 0x40, 0xeb, 0x9d,
@@ -246,7 +244,7 @@
   ioctl(uffd, UFFDIO_UNREGISTER, &uffd_unregister);
 }
 
-// Backup slow solution for the constructor. Fully decompresses and populates
+// Backup slow solution for the hook. Fully decompresses and populates
 // the cut range. This method is used if the userfaultfd setup failed to ensure
 // that the library will still function despite the failure.
 static void DecompressWholeRange(void* cut_start,
@@ -291,9 +289,11 @@
   return (void*)value;
 }
 
-void __attribute__((constructor(100))) InitLibraryDecompressor() {
+void __attribute__((constructor(0))) InitLibraryDecompressor() {
   // The constructor only works on 64 bit systems and as such expecting the
   // pointer size to be 8 bytes.
+  // The constructor priority is set to 0(the highest) to ensure that it starts
+  // as a first constructor.
   _Static_assert(sizeof(uint64_t) == sizeof(uintptr_t),
                  "Pointer size is not 8 bytes");
 
diff --git a/tools/android/elf_compression/elf_headers.py b/tools/android/elf_compression/elf_headers.py
index c517b19..ba5e026 100644
--- a/tools/android/elf_compression/elf_headers.py
+++ b/tools/android/elf_compression/elf_headers.py
@@ -416,11 +416,17 @@
     """Orders program LOAD headers by p_vaddr to comply with standard."""
 
     def HeaderToKey(phdr):
-      if phdr.p_type == ProgramHeader.Type.PT_LOAD:
+      # ELF standard required PT_INTERP and PT_PHDR to be strictly before
+      # PT_LOAD.
+      if phdr.p_type == ProgramHeader.Type.PT_INTERP:
         return (0, phdr.p_vaddr)
+      elif phdr.p_type == ProgramHeader.Type.PT_PHDR:
+        return (1, phdr.p_vaddr)
+      elif phdr.p_type == ProgramHeader.Type.PT_LOAD:
+        return (2, phdr.p_vaddr)
       else:
         # We want to preserve the order of non LOAD segments.
-        return (1, 0)
+        return (3, 0)
 
     self.phdrs.sort(key=HeaderToKey)
 
diff --git a/tools/android/elf_compression/test/compression_script_test.py b/tools/android/elf_compression/test/compression_script_test.py
index 8627734a..1e47bee 100755
--- a/tools/android/elf_compression/test/compression_script_test.py
+++ b/tools/android/elf_compression/test/compression_script_test.py
@@ -17,7 +17,7 @@
 LIBRARY_CC_NAME = 'libtest.cc'
 OPENER_CC_NAME = 'library_opener.cc'
 
-CONSTRUCTOR_C_PATH = '../constructor/library_constructor.c'
+CONSTRUCTOR_C_PATH = '../decompression_hook/decompression_hook.c'
 SCRIPT_PATH = '../compress_section.py'
 
 # src/third_party/llvm-build/Release+Asserts/bin/clang++
diff --git a/tools/binary_size/libsupersize/static/index.html b/tools/binary_size/libsupersize/static/index.html
index 3a737e28..665e7701 100644
--- a/tools/binary_size/libsupersize/static/index.html
+++ b/tools/binary_size/libsupersize/static/index.html
@@ -191,13 +191,17 @@
     return channel == 'stable/beta';
   }
 
+  function fmtCpuApk(cpu, apk) {
+    return cpu + '/' + apk;
+  }
+
   function cpuApkPairs(cpus, apks) {
     let out = [];
     for (let cpu of cpus) {
       for (let apk of apks) {
         // Chrome.apk not available for arm_64
         if(!(cpu == 'arm_64' && apk == 'Chrome.apk')) {
-          out.push(cpu + '/' + apk);
+          out.push(fmtCpuApk(cpu, apk));
         }
       }
     }
@@ -215,7 +219,7 @@
         // Can safely discard minimal apks - as of 16-Sep-2019 there was only
         // one entry with an attached Monochrome.minimal apk, assumed bug
         if (apk === 'Monochrome.minimal.apks') apk = 'Monochrome.apk';
-        return a.cpu + '/' + apk;
+        return fmtCpuApk(a.cpu, a.apk);
       }
       ))];
     }
@@ -231,20 +235,22 @@
     }
   }
 
-/*
- * @param {bool} swapping: True if this is driven by a canary <-> stable change
- */
   function updateVersions() {
+    const prev = selVersion1.value;
     let versions = [];
     if (channelIsMilestone()) {
       // For the selected APK
       versions = milestonesPushed.version;
     } else {
-      versions = officialBuildsPushed.map(a => a.version);
+      versions = (officialBuildsPushed
+        .filter(a => fmtCpuApk(a.cpu, a.apk) == selApk.value)
+        .map(a => a.version));
     }
     selVersion1.innerHTML = '';
     selVersion1.appendChild(buildOptions(versions));
-    selectOption(selVersion1.querySelectorAll('option'), -1);
+    // Selects latest version (index -1) if previous option not still in list.
+    selectOption(selVersion1.querySelectorAll('option'),
+                 versions.indexOf(prev));
   }
 
   function updateDiffVersions() {
@@ -267,12 +273,17 @@
   updateVersions();
   updateDiffVersions();
 
+  selApk.addEventListener('change', () => {
+    updateVersions();
+  });
+
   const selChannels = document.getElementsByName('mode');
   for(let i=0; i < selChannels.length; i++) {
     selChannels[i].addEventListener('click', () => {
       updateSubmitButton();
       updateApk();
       updateVersions();
+      selectOption(selVersion1.querySelectorAll('option'), -1);
       updateDiffVersions();
     });
   }
diff --git a/tools/binary_size/libsupersize/testdata/Archive.golden b/tools/binary_size/libsupersize/testdata/Archive.golden
index 82e6b4af..0d8851e5 100644
--- a/tools/binary_size/libsupersize/testdata/Archive.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive.golden
@@ -1,4 +1,4 @@
-Section .text: has 0.2% of 83792 bytes accounted for from 16 symbols. 35816920 bytes are unaccounted for.
+Section .text: has 0.2% of 83792 bytes accounted for from 16 symbols. 35898456 bytes are unaccounted for.
 * Padding accounts for 13808 bytes (16.5%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
 * 0 have a component assigned. Accounts for 0 bytes (0.0%).
diff --git a/tools/binary_size/libsupersize/testdata/Archive_Apk.golden b/tools/binary_size/libsupersize/testdata/Archive_Apk.golden
index 4335852..41cd944 100644
--- a/tools/binary_size/libsupersize/testdata/Archive_Apk.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive_Apk.golden
@@ -9,7 +9,7 @@
 linker_name=gold
 map_file_name=../../../test.map
 tool_prefix=tools/binary_size/libsupersize/testdata/mock_toolchain/
-Section .text: has 0.2% of 83792 bytes accounted for from 21 symbols. 35816920 bytes are unaccounted for.
+Section .text: has 0.2% of 83792 bytes accounted for from 21 symbols. 35898456 bytes are unaccounted for.
 * Padding accounts for 13808 bytes (16.5%)
 * 16 have source paths. Accounts for 73986 bytes (88.3%).
 * 16 have a component assigned. Accounts for 73986 bytes (88.3%).
@@ -71,8 +71,8 @@
 * 0 have source paths. Accounts for 0 bytes (0.0%).
 * 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
-Section .other: has 100.0% of 39228839 bytes accounted for from 5 symbols. 0 bytes are unaccounted for.
-* Padding accounts for 33984935 bytes (86.6%)
+Section .other: has 100.0% of 39147303 bytes accounted for from 5 symbols. 0 bytes are unaccounted for.
+* Padding accounts for 33903399 bytes (86.6%)
 * 3 have source paths. Accounts for 5243904 bytes (13.4%).
 * 1 have a component assigned. Accounts for 1048576 bytes (2.7%).
 * 0 symbols have shared ownership.
@@ -287,7 +287,7 @@
 .other@0(size_without_padding=1048576,padding=0,full_name=assets/icudtl.dat,object_path=,source_path=third_party/icu/android/icudtl.dat,flags={},num_aliases=1,component=Internal>Android)
 .other@0(size_without_padding=1024,padding=0,full_name=res/drawable-v13/test.xml,object_path=,source_path=chrome/android/res/drawable/test.xml,flags={},num_aliases=1,component=)
 .other@0(size_without_padding=0,padding=764,full_name=Overhead: APK file,object_path=,source_path=,flags={},num_aliases=1,component=)
-.other@0(size_without_padding=0,padding=33984171,full_name=Overhead: ELF file,object_path=,source_path=,flags={},num_aliases=1,component=)
+.other@0(size_without_padding=0,padding=33902635,full_name=Overhead: ELF file,object_path=,source_path=,flags={},num_aliases=1,component=)
 .rodata@266e600(size_without_padding=5,padding=0,full_name="Str1",object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=2,component=Blink>Internal)
 .rodata@266e600(size_without_padding=5,padding=0,full_name="Str1",object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=2,component=Internal>Android)
 .rodata@266e605(size_without_padding=16,padding=0,full_name="String literal2",object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=1,component=Internal>Android)
diff --git a/tools/binary_size/libsupersize/testdata/Archive_Elf.golden b/tools/binary_size/libsupersize/testdata/Archive_Elf.golden
index 71c8468..ae177c7 100644
--- a/tools/binary_size/libsupersize/testdata/Archive_Elf.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive_Elf.golden
@@ -7,7 +7,7 @@
 linker_name=gold
 map_file_name=../../../test.map
 tool_prefix=tools/binary_size/libsupersize/testdata/mock_toolchain/
-Section .text: has 0.2% of 83792 bytes accounted for from 21 symbols. 35816920 bytes are unaccounted for.
+Section .text: has 0.2% of 83792 bytes accounted for from 21 symbols. 35898456 bytes are unaccounted for.
 * Padding accounts for 13808 bytes (16.5%)
 * 16 have source paths. Accounts for 73986 bytes (88.3%).
 * 16 have a component assigned. Accounts for 73986 bytes (88.3%).
@@ -66,8 +66,8 @@
 * 0 have source paths. Accounts for 0 bytes (0.0%).
 * 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
-Section .other: has 100.0% of 33984171 bytes accounted for from 1 symbols. 0 bytes are unaccounted for.
-* Padding accounts for 33984171 bytes (100.0%)
+Section .other: has 100.0% of 33902635 bytes accounted for from 1 symbols. 0 bytes are unaccounted for.
+* Padding accounts for 33902635 bytes (100.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
 * 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
@@ -84,7 +84,7 @@
 .data.rel.ro.local@2c17740(size_without_padding=789904,padding=0,full_name=chrome::mojom::FieldTrialRecorderProxy [vtable],object_path=third_party/sub/ContiguousContainer.o,source_path=third_party/container/container.c,flags={},num_aliases=1,component=UI>Browser)
 .data.rel.ro.local@2cd84e0(size_without_padding=16,padding=16,full_name=.Lswitch.table.45,object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o,source_path=,flags={},num_aliases=1,component=)
 .data.rel.ro.local@2cd84f0(size_without_padding=8,padding=0,full_name=kSystemClassPrefixes,object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o,source_path=,flags={anon},num_aliases=1,component=)
-.other@0(size_without_padding=0,padding=33984171,full_name=Overhead: ELF file,object_path=,source_path=,flags={},num_aliases=1,component=)
+.other@0(size_without_padding=0,padding=33902635,full_name=Overhead: ELF file,object_path=,source_path=,flags={},num_aliases=1,component=)
 .rodata@266e600(size_without_padding=5,padding=0,full_name="Str1",object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=2,component=Blink>Internal)
 .rodata@266e600(size_without_padding=5,padding=0,full_name="Str1",object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=2,component=Internal>Android)
 .rodata@266e605(size_without_padding=16,padding=0,full_name="String literal2",object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=1,component=Internal>Android)
diff --git a/tools/binary_size/libsupersize/testdata/Archive_MinimalApks.golden b/tools/binary_size/libsupersize/testdata/Archive_MinimalApks.golden
index ffc0afa..cc1d32c 100644
--- a/tools/binary_size/libsupersize/testdata/Archive_MinimalApks.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive_MinimalApks.golden
@@ -10,7 +10,7 @@
 linker_name=gold
 map_file_name=../../../test.map
 tool_prefix=tools/binary_size/libsupersize/testdata/mock_toolchain/
-Section .text: has 0.2% of 83792 bytes accounted for from 21 symbols. 35816920 bytes are unaccounted for.
+Section .text: has 0.2% of 83792 bytes accounted for from 21 symbols. 35898456 bytes are unaccounted for.
 * Padding accounts for 13808 bytes (16.5%)
 * 16 have source paths. Accounts for 73986 bytes (88.3%).
 * 16 have a component assigned. Accounts for 73986 bytes (88.3%).
@@ -72,8 +72,8 @@
 * 0 have source paths. Accounts for 0 bytes (0.0%).
 * 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
-Section .other: has 100.0% of 39228839 bytes accounted for from 5 symbols. 0 bytes are unaccounted for.
-* Padding accounts for 33984935 bytes (86.6%)
+Section .other: has 100.0% of 39147303 bytes accounted for from 5 symbols. 0 bytes are unaccounted for.
+* Padding accounts for 33903399 bytes (86.6%)
 * 3 have source paths. Accounts for 5243904 bytes (13.4%).
 * 1 have a component assigned. Accounts for 1048576 bytes (2.7%).
 * 0 symbols have shared ownership.
@@ -288,7 +288,7 @@
 .other@0(size_without_padding=1048576,padding=0,full_name=assets/icudtl.dat,object_path=,source_path=third_party/icu/android/icudtl.dat,flags={},num_aliases=1,component=Internal>Android)
 .other@0(size_without_padding=1024,padding=0,full_name=res/drawable-v13/test.xml,object_path=,source_path=chrome/android/res/drawable/test.xml,flags={},num_aliases=1,component=)
 .other@0(size_without_padding=0,padding=764,full_name=Overhead: APK file,object_path=,source_path=,flags={},num_aliases=1,component=)
-.other@0(size_without_padding=0,padding=33984171,full_name=Overhead: ELF file,object_path=,source_path=,flags={},num_aliases=1,component=)
+.other@0(size_without_padding=0,padding=33902635,full_name=Overhead: ELF file,object_path=,source_path=,flags={},num_aliases=1,component=)
 .rodata@266e600(size_without_padding=5,padding=0,full_name="Str1",object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=2,component=Blink>Internal)
 .rodata@266e600(size_without_padding=5,padding=0,full_name="Str1",object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=2,component=Internal>Android)
 .rodata@266e605(size_without_padding=16,padding=0,full_name="String literal2",object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=1,component=Internal>Android)
diff --git a/tools/binary_size/libsupersize/testdata/Archive_OutputDirectory.golden b/tools/binary_size/libsupersize/testdata/Archive_OutputDirectory.golden
index 3094a1a..ec4971fd 100644
--- a/tools/binary_size/libsupersize/testdata/Archive_OutputDirectory.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive_OutputDirectory.golden
@@ -1,4 +1,4 @@
-Section .text: has 0.2% of 83792 bytes accounted for from 16 symbols. 35816920 bytes are unaccounted for.
+Section .text: has 0.2% of 83792 bytes accounted for from 16 symbols. 35898456 bytes are unaccounted for.
 * Padding accounts for 13808 bytes (16.5%)
 * 14 have source paths. Accounts for 74034 bytes (88.4%).
 * 14 have a component assigned. Accounts for 74034 bytes (88.4%).
diff --git a/tools/binary_size/libsupersize/testdata/Archive_Pak_Files.golden b/tools/binary_size/libsupersize/testdata/Archive_Pak_Files.golden
index ce5b255..92b2dfe 100644
--- a/tools/binary_size/libsupersize/testdata/Archive_Pak_Files.golden
+++ b/tools/binary_size/libsupersize/testdata/Archive_Pak_Files.golden
@@ -7,7 +7,7 @@
 linker_name=gold
 map_file_name=../../../test.map
 tool_prefix=tools/binary_size/libsupersize/testdata/mock_toolchain/
-Section .text: has 0.2% of 83792 bytes accounted for from 21 symbols. 35816920 bytes are unaccounted for.
+Section .text: has 0.2% of 83792 bytes accounted for from 21 symbols. 35898456 bytes are unaccounted for.
 * Padding accounts for 13808 bytes (16.5%)
 * 16 have source paths. Accounts for 73986 bytes (88.3%).
 * 16 have a component assigned. Accounts for 73986 bytes (88.3%).
@@ -68,8 +68,8 @@
 * 0 have source paths. Accounts for 0 bytes (0.0%).
 * 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
-Section .other: has 100.0% of 33984171 bytes accounted for from 1 symbols. 0 bytes are unaccounted for.
-* Padding accounts for 33984171 bytes (100.0%)
+Section .other: has 100.0% of 33902635 bytes accounted for from 1 symbols. 0 bytes are unaccounted for.
+* Padding accounts for 33902635 bytes (100.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
 * 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
@@ -86,7 +86,7 @@
 .data.rel.ro.local@2c17740(size_without_padding=789904,padding=0,full_name=chrome::mojom::FieldTrialRecorderProxy [vtable],object_path=third_party/sub/ContiguousContainer.o,source_path=third_party/container/container.c,flags={},num_aliases=1,component=UI>Browser)
 .data.rel.ro.local@2cd84e0(size_without_padding=16,padding=16,full_name=.Lswitch.table.45,object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libcontroller_api_impl.a_controller_api_impl.o,source_path=,flags={},num_aliases=1,component=)
 .data.rel.ro.local@2cd84f0(size_without_padding=8,padding=0,full_name=kSystemClassPrefixes,object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o,source_path=,flags={anon},num_aliases=1,component=)
-.other@0(size_without_padding=0,padding=33984171,full_name=Overhead: ELF file,object_path=,source_path=,flags={},num_aliases=1,component=)
+.other@0(size_without_padding=0,padding=33902635,full_name=Overhead: ELF file,object_path=,source_path=,flags={},num_aliases=1,component=)
 .rodata@266e600(size_without_padding=5,padding=0,full_name="Str1",object_path=base/base/page_allocator.o,source_path=base/page_allocator.cc,flags={},num_aliases=2,component=Blink>Internal)
 .rodata@266e600(size_without_padding=5,padding=0,full_name="Str1",object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=2,component=Internal>Android)
 .rodata@266e605(size_without_padding=16,padding=0,full_name="String literal2",object_path=third_party/icu/icuuc/ucnv_ext.o,source_path=third_party/icu/ucnv_ext.c,flags={gen},num_aliases=1,component=Internal>Android)
diff --git a/tools/binary_size/libsupersize/testdata/Console.golden b/tools/binary_size/libsupersize/testdata/Console.golden
index 5d58f265..5002696 100644
--- a/tools/binary_size/libsupersize/testdata/Console.golden
+++ b/tools/binary_size/libsupersize/testdata/Console.golden
@@ -78,19 +78,19 @@
     .bss: 1.24mb (1300456 bytes) (not included in totals)
     .data: 99.4kb (101768 bytes) (0.1%)
     .data.rel.ro: 1.02mb (1065224 bytes) (0.8%)
-    .other: 32.4mb (33984171 bytes) (25.3%)
+    .other: 32.3mb (33902635 bytes) (25.3%)
     .rel.dyn: 2.53mb (2655384 bytes) (2.0%)
     .rodata: 5.65mb (5927652 bytes) (4.4%)
     .strtab: 33.2mb (34841854 bytes) (26.0%)
     .symtab: 16.4mb (17166112 bytes) (12.8%)
-    .text: 34.2mb (35900712 bytes) (26.7%)
+    .text: 34.3mb (35982248 bytes) (26.8%)
 
-Showing 51 symbols (45 unique) with total pss: 37499787 bytes
+Showing 51 symbols (45 unique) with total pss: 37418251 bytes
 Histogram of symbols based on PSS:
      [2,4): 7    [16,32): 12     [128,256): 2      [8192,16384): 1     [262144,524288): 1   [33554432,67108864): 1
      [4,8): 6    [32,64): 9      [256,512): 1    [65536,131072): 1    [524288,1048576): 2
     [8,16): 3   [64,128): 1    [2048,4096): 1   [131072,262144): 2   [1048576,2097152): 1
-Sizes: .text=81.8kb     .rodata=2.52mb     .data.rel.ro=92 bytes   .data=168 bytes  .bss=512kb      .other=32.4mb     total=35.8mb
+Sizes: .text=81.8kb     .rodata=2.52mb     .data.rel.ro=92 bytes   .data=168 bytes  .bss=512kb      .other=32.3mb     total=35.7mb
 Counts: .text=21 .rodata=11 .data.rel.ro=3 .data=5 .bss=6 .other=1
 Number of unique paths: 9
 
@@ -123,78 +123,78 @@
              .Lswitch.table.45
 12)    790284 (2.1%)  R@0x2cd84f0  8              third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o
              kSystemClassPrefixes
-13)  34774455 (92.7%) o@0x0        33984171       {no path}
+13)  34692919 (92.7%) o@0x0        33902635       {no path}
              Overhead: ELF file
-14)  34774457 (92.7%) r@0x266e600  2.5 (size=5)   base/page_allocator.cc
+14)  34692921 (92.7%) r@0x266e600  2.5 (size=5)   base/page_allocator.cc
              "Str1" (num_aliases=2)
-15)  34774460 (92.7%) r@0x266e600  2.5 (size=5)   $root_gen_dir/third_party/icu/ucnv_ext.c
+15)  34692924 (92.7%) r@0x266e600  2.5 (size=5)   $root_gen_dir/third_party/icu/ucnv_ext.c
              "Str1" (num_aliases=2)
-16)  34774476 (92.7%) r@0x266e605  16             $root_gen_dir/third_party/icu/ucnv_ext.c
+16)  34692940 (92.7%) r@0x266e605  16             $root_gen_dir/third_party/icu/ucnv_ext.c
              "String literal2"
-17)  34774519 (92.7%) r@0x266e630  43             {no path}
+17)  34692983 (92.7%) r@0x266e630  43             {no path}
              ** merge strings
-18)  36739864 (98.0%) r@0x284d600  1965345        {no path}
+18)  36658328 (98.0%) r@0x284d600  1965345        {no path}
              ** merge constants
-19)  36739867 (98.0%) r@0x284e364  3              {no path}
+19)  36658331 (98.0%) r@0x284e364  3              {no path}
              ** symbol gap 0
-20)  36739875 (98.0%) r@0x284e364  8              base/page_allocator.cc
-21)  36739919 (98.0%) r@0x284e370  44             base/page_allocator.cc
+20)  36658339 (98.0%) r@0x284e364  8              base/page_allocator.cc
+21)  36658383 (98.0%) r@0x284e370  44             base/page_allocator.cc
              Name
-22)  36739951 (98.0%) r@0x284e398  32             third_party/container/container.c
+22)  36658415 (98.0%) r@0x284e398  32             third_party/container/container.c
              chrome::mojom::FilePatcher::Name_
-23)  37415991 (99.8%) r@0x28f3450  676040         third_party/paint.cc
+23)  37334455 (99.8%) r@0x28f3450  676040         third_party/paint.cc
              kAnimationFrameTimeHistogramClassPath
-24)  37415995 (99.8%) r@0x28f3480  4              third_party/paint.cc
+24)  37334459 (99.8%) r@0x28f3480  4              third_party/paint.cc
              blink::CSSValueKeywordsHash::findValueImpl::value_word_list
-25)  37416011 (99.8%) t@0x28d900   16             base/page_allocator.cc
+25)  37334475 (99.8%) t@0x28d900   16             base/page_allocator.cc
              _GLOBAL__sub_I_page_allocator.cc
-26)  37416067 (99.8%) t@0x28d910   56             base/page_allocator.cc
+26)  37334531 (99.8%) t@0x28d910   56             base/page_allocator.cc
              _GLOBAL__sub_I_bbr_sender.cc
-27)  37416095 (99.8%) t@0x28d948   28             base/page_allocator.cc
+27)  37334559 (99.8%) t@0x28d948   28             base/page_allocator.cc
              _GLOBAL__sub_I_pacing_sender.cc
-28)  37416133 (99.8%) t@0x28d964   38             base/page_allocator.cc
+28)  37334597 (99.8%) t@0x28d964   38             base/page_allocator.cc
              extFromUUseMapping
-29)  37416165 (99.8%) t@0x28d98a   32             base/page_allocator.cc
+29)  37334629 (99.8%) t@0x28d98a   32             base/page_allocator.cc
              extFromUUseMapping
-30)  37425923 (99.8%) t@Group      9758           {no path}
+30)  37344387 (99.8%) t@Group      9758           {no path}
              ** symbol gaps (count=2)
-31)  37426371 (99.8%) t@0x28f000   448            $root_gen_dir/third_party/icu/ucnv_ext.c
+31)  37344835 (99.8%) t@0x28f000   448            $root_gen_dir/third_party/icu/ucnv_ext.c
              ucnv_extMatchFromU
-32)  37426399 (99.8%) t@0x28f1c8   28             $root_gen_dir/third_party/icu/ucnv_ext.c
+32)  37344863 (99.8%) t@0x28f1c8   28             $root_gen_dir/third_party/icu/ucnv_ext.c
              _GLOBAL__sub_I_SkDeviceProfile.cpp
-33)  37495523 (100.0%) t@0x28f1e0   69124          $root_gen_dir/third_party/icu/ucnv_ext.c
+33)  37413987 (100.0%) t@0x28f1e0   69124          $root_gen_dir/third_party/icu/ucnv_ext.c
              foo_bar
-34)  37495547 (100.0%) t@0x2a0000   24 (size=48)   $root_gen_dir/third_party/icu/ucnv_ext.c
+34)  37414011 (100.0%) t@0x2a0000   24 (size=48)   $root_gen_dir/third_party/icu/ucnv_ext.c
              BazAlias (num_aliases=2)
-35)  37495571 (100.0%) t@0x2a0000   24 (size=48)   {no path}
+35)  37414035 (100.0%) t@0x2a0000   24 (size=48)   {no path}
              blink::ContiguousContainerBase::shrinkToFit (num_aliases=2)
-36)  37495574 (100.0%) t@0x2a0010   3 (size=12)    third_party/fft_float.cc
+36)  37414038 (100.0%) t@0x2a0010   3 (size=12)    third_party/fft_float.cc
              BarAlias (num_aliases=4)
-37)  37495577 (100.0%) t@0x2a0010   3 (size=12)    third_party/fft_float.cc
+37)  37414041 (100.0%) t@0x2a0010   3 (size=12)    third_party/fft_float.cc
              FooAlias (num_aliases=4)
-38)  37495580 (100.0%) t@0x2a0010   3 (size=12)    $root_gen_dir/third_party/icu/ucnv_ext.c
+38)  37414044 (100.0%) t@0x2a0010   3 (size=12)    $root_gen_dir/third_party/icu/ucnv_ext.c
              blink::ContiguousContainerBase::shrinkToFit (num_aliases=4)
-39)  37495583 (100.0%) t@0x2a0010   3 (size=12)    third_party/paint.cc
+39)  37414047 (100.0%) t@0x2a0010   3 (size=12)    third_party/paint.cc
              blink::ContiguousContainerBase::shrinkToFit (num_aliases=4)
-40)  37495611 (100.0%) t@0x2a0020   28             third_party/container/container.c
+40)  37414075 (100.0%) t@0x2a0020   28             third_party/container/container.c
              blink::ContiguousContainerBase::ContiguousContainerBase
-41)  37495705 (100.0%) t@0x2a1000   94             third_party/container/container.c
+41)  37414169 (100.0%) t@0x2a1000   94             third_party/container/container.c
              blink::PaintChunker::releasePaintChunks
-42)  37499739 (100.0%) t@0x2a2000   4034           third_party/container/container.c
+42)  37418203 (100.0%) t@0x2a2000   4034           third_party/container/container.c
              ** outlined function
-43)  37499763 (100.0%) t@0x2a2020   24 (size=48)   {no path}
+43)  37418227 (100.0%) t@0x2a2020   24 (size=48)   {no path}
              ** outlined function * 2 (num_aliases=2)
-44)  37499787 (100.0%) t@0x2a2020   24 (size=48)   {no path}
+44)  37418251 (100.0%) t@0x2a2020   24 (size=48)   {no path}
              aliasedWithOutlinedFunction (num_aliases=2)
-45)  37499787 (100.0%) b@0x0        262144         third_party/fft_float.cc
+45)  37418251 (100.0%) b@0x0        262144         third_party/fft_float.cc
              ff_cos_131072
-46)  37499787 (100.0%) b@0x0        131072         third_party/fft_fixed.cc
+46)  37418251 (100.0%) b@0x0        131072         third_party/fft_fixed.cc
              ff_cos_131072_fixed
-47)  37499787 (100.0%) b@0x0        131072         third_party/fft_float.cc
+47)  37418251 (100.0%) b@0x0        131072         third_party/fft_float.cc
              ff_cos_65536
-48)  37499787 (100.0%) b@0x2dffda0  28             $root_gen_dir/third_party/icu/ucnv_ext.c
+48)  37418251 (100.0%) b@0x2dffda0  28             $root_gen_dir/third_party/icu/ucnv_ext.c
              g_chrome_content_browser_client
-49)  37499787 (100.0%) b@0x2dffe80  200            $root_gen_dir/third_party/icu/ucnv_ext.c
+49)  37418251 (100.0%) b@0x2dffe80  200            $root_gen_dir/third_party/icu/ucnv_ext.c
              SaveHistogram::atomic_histogram_pointer
-50)  37499787 (100.0%) b@0x2dffe84  4              $root_gen_dir/third_party/icu/ucnv_ext.c
+50)  37418251 (100.0%) b@0x2dffe84  4              $root_gen_dir/third_party/icu/ucnv_ext.c
              g_AnimationFrameTimeHistogram_clazz
diff --git a/tools/binary_size/libsupersize/testdata/Csv.golden b/tools/binary_size/libsupersize/testdata/Csv.golden
index 07f40e9..cdf9feb 100644
--- a/tools/binary_size/libsupersize/testdata/Csv.golden
+++ b/tools/binary_size/libsupersize/testdata/Csv.golden
@@ -3,12 +3,12 @@
 .bss,1300456
 .data,101768
 .data.rel.ro,1065224
-.other,33984171
+.other,33902635
 .rel.dyn,2655384
 .rodata,5927652
 .strtab,34841854
 .symtab,17166112
-.text,35900712
+.text,35982248
 
 GroupCount,Address,SizeWithoutPadding,Padding,NumAliases,PSS,Section,Name
 ,0x2de7000,4,0,1,4.0,d,google::protobuf::internal::pLinuxKernelCmpxchg
@@ -24,7 +24,7 @@
 ,0x2c17740,789904,0,1,789904.0,R,chrome::mojom::FieldTrialRecorderProxy [vtable]
 ,0x2cd84e0,16,16,1,32.0,R,.Lswitch.table.45
 ,0x2cd84f0,8,0,1,8.0,R,kSystemClassPrefixes
-,0x0,0,33984171,1,33984171.0,o,Overhead: ELF file
+,0x0,0,33902635,1,33902635.0,o,Overhead: ELF file
 ,0x266e600,5,0,2,2.5,r,"""Str1"""
 ,0x266e600,5,0,2,2.5,r,"""Str1"""
 ,0x266e605,16,0,1,16.0,r,"""String literal2"""
diff --git a/tools/binary_size/libsupersize/testdata/FullDescription.golden b/tools/binary_size/libsupersize/testdata/FullDescription.golden
index 14b93d1b..7453f51 100644
--- a/tools/binary_size/libsupersize/testdata/FullDescription.golden
+++ b/tools/binary_size/libsupersize/testdata/FullDescription.golden
@@ -14,12 +14,12 @@
     .bss: 1.24mb (1300456 bytes) (not included in totals)
     .data: 99.4kb (101768 bytes) (0.1%)
     .data.rel.ro: 1.02mb (1065224 bytes) (0.8%)
-    .other: 32.4mb (33984171 bytes) (25.3%)
+    .other: 32.3mb (33902635 bytes) (25.3%)
     .rel.dyn: 2.53mb (2655384 bytes) (2.0%)
     .rodata: 5.65mb (5927652 bytes) (4.4%)
     .strtab: 33.2mb (34841854 bytes) (26.0%)
     .symtab: 16.4mb (17166112 bytes) (12.8%)
-    .text: 34.2mb (35900712 bytes) (26.7%)
+    .text: 34.3mb (35982248 bytes) (26.8%)
 
 Other section sizes:
     .ARM.attributes: 60 bytes (60 bytes)
@@ -42,7 +42,7 @@
     .rel.plt: 2.75kb (2816 bytes)
     .shstrtab: 436 bytes (436 bytes)
 
-Section .text: has 0.2% of 83792 bytes accounted for from 21 symbols. 35816920 bytes are unaccounted for.
+Section .text: has 0.2% of 83792 bytes accounted for from 21 symbols. 35898456 bytes are unaccounted for.
 * Padding accounts for 13808 bytes (16.5%)
 * 16 have source paths. Accounts for 73986 bytes (88.3%).
 * 16 have a component assigned. Accounts for 73986 bytes (88.3%).
@@ -101,18 +101,18 @@
 * 0 have source paths. Accounts for 0 bytes (0.0%).
 * 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
-Section .other: has 100.0% of 33984171 bytes accounted for from 1 symbols. 0 bytes are unaccounted for.
-* Padding accounts for 33984171 bytes (100.0%)
+Section .other: has 100.0% of 33902635 bytes accounted for from 1 symbols. 0 bytes are unaccounted for.
+* Padding accounts for 33902635 bytes (100.0%)
 * 0 have source paths. Accounts for 0 bytes (0.0%).
 * 0 have a component assigned. Accounts for 0 bytes (0.0%).
 * 0 symbols have shared ownership.
 
-Showing 52 symbols (46 unique) with total pss: 37499787 bytes
+Showing 52 symbols (46 unique) with total pss: 37418251 bytes
 Histogram of symbols based on PSS:
      [2,4): 7    [16,32): 12     [128,256): 2       [4096,8192): 1     [262144,524288): 1   [33554432,67108864): 1
      [4,8): 6    [32,64): 9      [256,512): 1    [65536,131072): 1    [524288,1048576): 2
     [8,16): 3   [64,128): 1    [2048,4096): 2   [131072,262144): 2   [1048576,2097152): 1
-Sizes: .text=81.8kb     .rodata=2.52mb     .data.rel.ro=92 bytes   .data=168 bytes  .bss=512kb      .other=32.4mb     total=35.8mb
+Sizes: .text=81.8kb     .rodata=2.52mb     .data.rel.ro=92 bytes   .data=168 bytes  .bss=512kb      .other=32.3mb     total=35.7mb
 Counts: .text=21 .rodata=11 .data.rel.ro=3 .data=5 .bss=6 .other=1
 Number of unique paths: 9
 
@@ -158,142 +158,142 @@
 12)    790284 (2.1%)  R@0x2cd84f0  pss=8  padding=0  num_aliases=1
              source_path= 	object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o
              flags={anon}  name=kSystemClassPrefixes
-13)  34774455 (92.7%) o@0x0        pss=33984171  padding=33984171  num_aliases=1
+13)  34692919 (92.7%) o@0x0        pss=33902635  padding=33902635  num_aliases=1
              source_path= 	object_path=
              flags={}  name=Overhead: ELF file
-14)  34774457 (92.7%) r@0x266e600  pss=2.5 (size=5)  padding=0  num_aliases=2
+14)  34692921 (92.7%) r@0x266e600  pss=2.5 (size=5)  padding=0  num_aliases=2
              source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
              flags={}  name="Str1"
-15)  34774460 (92.7%) r@0x266e600  pss=2.5 (size=5)  padding=0  num_aliases=2
+15)  34692924 (92.7%) r@0x266e600  pss=2.5 (size=5)  padding=0  num_aliases=2
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={gen}  name="Str1"
-16)  34774476 (92.7%) r@0x266e605  pss=16  padding=0  num_aliases=1
+16)  34692940 (92.7%) r@0x266e605  pss=16  padding=0  num_aliases=1
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={gen}  name="String literal2"
-17)  34774519 (92.7%) r@0x266e630  pss=43  padding=27  num_aliases=1
+17)  34692983 (92.7%) r@0x266e630  pss=43  padding=27  num_aliases=1
              source_path= 	object_path=
              flags={}  name=** merge strings
-18)  36739864 (98.0%) r@0x284d600  pss=1965345  padding=1961920  num_aliases=1
+18)  36658328 (98.0%) r@0x284d600  pss=1965345  padding=1961920  num_aliases=1
              source_path= 	object_path=
              flags={}  name=** merge constants
-19)  36739867 (98.0%) r@0x284e364  pss=3  padding=3  num_aliases=1
+19)  36658331 (98.0%) r@0x284e364  pss=3  padding=3  num_aliases=1
              source_path= 	object_path=
              flags={}  name=** symbol gap 0
-20)  36739875 (98.0%) r@0x284e364  pss=8  padding=0  num_aliases=1
+20)  36658339 (98.0%) r@0x284e364  pss=8  padding=0  num_aliases=1
              source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
-21)  36739919 (98.0%) r@0x284e370  pss=44  padding=4  num_aliases=1
+21)  36658383 (98.0%) r@0x284e370  pss=44  padding=4  num_aliases=1
              source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
              flags={}  name=Name
-22)  36739951 (98.0%) r@0x284e398  pss=32  padding=0  num_aliases=1
+22)  36658415 (98.0%) r@0x284e398  pss=32  padding=0  num_aliases=1
              source_path=third_party/container/container.c 	object_path=third_party/sub/ContiguousContainer.o
              flags={}  name=chrome::mojom::FilePatcher::Name_
-23)  37415991 (99.8%) r@0x28f3450  pss=676040  padding=675992  num_aliases=1
+23)  37334455 (99.8%) r@0x28f3450  pss=676040  padding=675992  num_aliases=1
              source_path=third_party/paint.cc 	object_path=third_party/sub/PaintChunker.o
              flags={anon}  name=kAnimationFrameTimeHistogramClassPath
-24)  37415995 (99.8%) r@0x28f3480  pss=4  padding=0  num_aliases=1
+24)  37334459 (99.8%) r@0x28f3480  pss=4  padding=0  num_aliases=1
              source_path=third_party/paint.cc 	object_path=third_party/sub/PaintChunker.o
              flags={anon}  name=blink::CSSValueKeywordsHash::findValueImpl::value_word_list
                   full_name=blink::CSSValueKeywordsHash::findValueImpl(char const*, unsigned int)::value_word_list
-25)  37416011 (99.8%) t@0x28d900   pss=16  padding=0  num_aliases=1
+25)  37334475 (99.8%) t@0x28d900   pss=16  padding=0  num_aliases=1
              source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
              flags={startup}  name=_GLOBAL__sub_I_page_allocator.cc
-26)  37416067 (99.8%) t@0x28d910   pss=56  padding=0  num_aliases=1
+26)  37334531 (99.8%) t@0x28d910   pss=56  padding=0  num_aliases=1
              source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
              flags={startup}  name=_GLOBAL__sub_I_bbr_sender.cc
-27)  37416095 (99.8%) t@0x28d948   pss=28  padding=0  num_aliases=1
+27)  37334559 (99.8%) t@0x28d948   pss=28  padding=0  num_aliases=1
              source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
              flags={startup}  name=_GLOBAL__sub_I_pacing_sender.cc
-28)  37416133 (99.8%) t@0x28d964   pss=38  padding=0  num_aliases=1
+28)  37334597 (99.8%) t@0x28d964   pss=38  padding=0  num_aliases=1
              source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
              flags={}  name=extFromUUseMapping
                   full_name=extFromUUseMapping(signed char, unsigned int, int)
-29)  37416165 (99.8%) t@0x28d98a   pss=32  padding=0  num_aliases=1
+29)  37334629 (99.8%) t@0x28d98a   pss=32  padding=0  num_aliases=1
              source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
              flags={}  name=extFromUUseMapping
                   full_name=extFromUUseMapping(aj, int)
-30)  37421883 (99.8%) t@0x28f000   pss=5718  padding=5718  num_aliases=1
+30)  37340347 (99.8%) t@0x28f000   pss=5718  padding=5718  num_aliases=1
              source_path= 	object_path=
              flags={}  name=** symbol gap 0
-31)  37422331 (99.8%) t@0x28f000   pss=448  padding=0  num_aliases=1
+31)  37340795 (99.8%) t@0x28f000   pss=448  padding=0  num_aliases=1
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={gen}  name=ucnv_extMatchFromU
                   full_name=ucnv_extMatchFromU(int const*, int, unsigned short const*, int, unsigned short const*, int, unsigned int*, signed char, signed char)
-32)  37422359 (99.8%) t@0x28f1c8   pss=28  padding=8  num_aliases=1
+32)  37340823 (99.8%) t@0x28f1c8   pss=28  padding=8  num_aliases=1
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={startup,gen}  name=_GLOBAL__sub_I_SkDeviceProfile.cpp
-33)  37491483 (100.0%) t@0x28f1e0   pss=69124  padding=4  num_aliases=1
+33)  37409947 (100.0%) t@0x28f1e0   pss=69124  padding=4  num_aliases=1
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={unlikely,gen}  name=foo_bar
-34)  37491507 (100.0%) t@0x2a0000   pss=24 (size=48)  padding=32  num_aliases=2
+34)  37409971 (100.0%) t@0x2a0000   pss=24 (size=48)  padding=32  num_aliases=2
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={gen}  name=BazAlias
                   full_name=BazAlias(bool)
-35)  37491531 (100.0%) t@0x2a0000   pss=24 (size=48)  padding=32  num_aliases=2
+35)  37409995 (100.0%) t@0x2a0000   pss=24 (size=48)  padding=32  num_aliases=2
              source_path= 	object_path=
              flags={}  name=blink::ContiguousContainerBase::shrinkToFit
                   full_name=blink::ContiguousContainerBase::shrinkToFit()
-36)  37491534 (100.0%) t@0x2a0010   pss=3 (size=12)  padding=0  num_aliases=4
+36)  37409998 (100.0%) t@0x2a0010   pss=3 (size=12)  padding=0  num_aliases=4
              source_path=third_party/fft_float.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o
              flags={}  name=BarAlias
                   full_name=BarAlias()
-37)  37491537 (100.0%) t@0x2a0010   pss=3 (size=12)  padding=0  num_aliases=4
+37)  37410001 (100.0%) t@0x2a0010   pss=3 (size=12)  padding=0  num_aliases=4
              source_path=third_party/fft_float.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o
              flags={}  name=FooAlias
                   full_name=FooAlias()
-38)  37491540 (100.0%) t@0x2a0010   pss=3 (size=12)  padding=0  num_aliases=4
+38)  37410004 (100.0%) t@0x2a0010   pss=3 (size=12)  padding=0  num_aliases=4
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={gen,clone}  name=blink::ContiguousContainerBase::shrinkToFit
                   full_name=blink::ContiguousContainerBase::shrinkToFit()
-39)  37491543 (100.0%) t@0x2a0010   pss=3 (size=12)  padding=0  num_aliases=4
+39)  37410007 (100.0%) t@0x2a0010   pss=3 (size=12)  padding=0  num_aliases=4
              source_path=third_party/paint.cc 	object_path=third_party/sub/PaintChunker.o
              flags={clone}  name=blink::ContiguousContainerBase::shrinkToFit
                   full_name=blink::ContiguousContainerBase::shrinkToFit()
-40)  37491571 (100.0%) t@0x2a0020   pss=28  padding=4  num_aliases=1
+40)  37410035 (100.0%) t@0x2a0020   pss=28  padding=4  num_aliases=1
              source_path=third_party/container/container.c 	object_path=third_party/sub/ContiguousContainer.o
              flags={}  name=blink::ContiguousContainerBase::ContiguousContainerBase
                   full_name=blink::ContiguousContainerBase::ContiguousContainerBase(blink::ContiguousContainerBase&&)
-41)  37495611 (100.0%) t@0x2a1000   pss=4040  padding=4040  num_aliases=1
+41)  37414075 (100.0%) t@0x2a1000   pss=4040  padding=4040  num_aliases=1
              source_path= 	object_path=
              flags={}  name=** symbol gap 1
-42)  37495705 (100.0%) t@0x2a1000   pss=94  padding=0  num_aliases=1
+42)  37414169 (100.0%) t@0x2a1000   pss=94  padding=0  num_aliases=1
              source_path=third_party/container/container.c 	object_path=third_party/sub/ContiguousContainer.o
              flags={anon,clone}  name=blink::PaintChunker::releasePaintChunks
                   full_name=blink::PaintChunker::releasePaintChunks()
-43)  37499739 (100.0%) t@0x2a2000   pss=4034  padding=4002  num_aliases=1
+43)  37418203 (100.0%) t@0x2a2000   pss=4034  padding=4002  num_aliases=1
              source_path=third_party/container/container.c 	object_path=third_party/sub/ContiguousContainer.o
              flags={}  name=** outlined function
-44)  37499763 (100.0%) t@0x2a2020   pss=24 (size=48)  padding=0  num_aliases=2
+44)  37418227 (100.0%) t@0x2a2020   pss=24 (size=48)  padding=0  num_aliases=2
              source_path= 	object_path=
              flags={}  name=** outlined function * 2
-45)  37499787 (100.0%) t@0x2a2020   pss=24 (size=48)  padding=0  num_aliases=2
+45)  37418251 (100.0%) t@0x2a2020   pss=24 (size=48)  padding=0  num_aliases=2
              source_path= 	object_path=
              flags={}  name=aliasedWithOutlinedFunction
                   full_name=aliasedWithOutlinedFunction()
-46)  37499787 (100.0%) b@0x0        pss=262144  padding=0  num_aliases=1
+46)  37418251 (100.0%) b@0x0        pss=262144  padding=0  num_aliases=1
              source_path=third_party/fft_float.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o
              flags={}  name=ff_cos_131072
-47)  37499787 (100.0%) b@0x0        pss=131072  padding=0  num_aliases=1
+47)  37418251 (100.0%) b@0x0        pss=131072  padding=0  num_aliases=1
              source_path=third_party/fft_fixed.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_fixed.o
              flags={}  name=ff_cos_131072_fixed
-48)  37499787 (100.0%) b@0x0        pss=131072  padding=0  num_aliases=1
+48)  37418251 (100.0%) b@0x0        pss=131072  padding=0  num_aliases=1
              source_path=third_party/fft_float.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o
              flags={}  name=ff_cos_65536
-49)  37499787 (100.0%) b@0x2dffda0  pss=28  padding=0  num_aliases=1
+49)  37418251 (100.0%) b@0x2dffda0  pss=28  padding=0  num_aliases=1
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={gen}  name=g_chrome_content_browser_client
-50)  37499787 (100.0%) b@0x2dffe80  pss=200  padding=196  num_aliases=1
+50)  37418251 (100.0%) b@0x2dffe80  pss=200  padding=196  num_aliases=1
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={gen}  name=SaveHistogram::atomic_histogram_pointer
                   full_name=SaveHistogram(_JNIEnv*, base::android::JavaParamRef<_jobject*> const&, base::android::JavaParamRef<_jstring*> const&, base::android::JavaParamRef<_jlongArray*> const&, int)::atomic_histogram_pointer
-51)  37499787 (100.0%) b@0x2dffe84  pss=4  padding=0  num_aliases=1
+51)  37418251 (100.0%) b@0x2dffe84  pss=4  padding=0  num_aliases=1
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={anon,gen}  name=g_AnimationFrameTimeHistogram_clazz
-Showing 51 symbols (45 unique) with total pss: 37499787 bytes
+Showing 51 symbols (45 unique) with total pss: 37418251 bytes
 Histogram of symbols based on PSS:
      [2,4): 7    [16,32): 12     [128,256): 2      [8192,16384): 1     [262144,524288): 1   [33554432,67108864): 1
      [4,8): 6    [32,64): 9      [256,512): 1    [65536,131072): 1    [524288,1048576): 2
     [8,16): 3   [64,128): 1    [2048,4096): 1   [131072,262144): 2   [1048576,2097152): 1
-Sizes: .text=81.8kb     .rodata=2.52mb     .data.rel.ro=92 bytes   .data=168 bytes  .bss=512kb      .other=32.4mb     total=35.8mb
+Sizes: .text=81.8kb     .rodata=2.52mb     .data.rel.ro=92 bytes   .data=168 bytes  .bss=512kb      .other=32.3mb     total=35.7mb
 Counts: .text=21 .rodata=11 .data.rel.ro=3 .data=5 .bss=6 .other=1
 Number of unique paths: 9
 
@@ -339,60 +339,60 @@
 12)    790284 (2.1%)  R@0x2cd84f0  pss=8  padding=0  num_aliases=1
              source_path= 	object_path=third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o
              flags={anon}  name=kSystemClassPrefixes
-13)  34774455 (92.7%) o@0x0        pss=33984171  padding=33984171  num_aliases=1
+13)  34692919 (92.7%) o@0x0        pss=33902635  padding=33902635  num_aliases=1
              source_path= 	object_path=
              flags={}  name=Overhead: ELF file
-14)  34774457 (92.7%) r@0x266e600  pss=2.5 (size=5)  padding=0  num_aliases=2
+14)  34692921 (92.7%) r@0x266e600  pss=2.5 (size=5)  padding=0  num_aliases=2
              source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
              flags={}  name="Str1"
-15)  34774460 (92.7%) r@0x266e600  pss=2.5 (size=5)  padding=0  num_aliases=2
+15)  34692924 (92.7%) r@0x266e600  pss=2.5 (size=5)  padding=0  num_aliases=2
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={gen}  name="Str1"
-16)  34774476 (92.7%) r@0x266e605  pss=16  padding=0  num_aliases=1
+16)  34692940 (92.7%) r@0x266e605  pss=16  padding=0  num_aliases=1
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={gen}  name="String literal2"
-17)  34774519 (92.7%) r@0x266e630  pss=43  padding=27  num_aliases=1
+17)  34692983 (92.7%) r@0x266e630  pss=43  padding=27  num_aliases=1
              source_path= 	object_path=
              flags={}  name=** merge strings
-18)  36739864 (98.0%) r@0x284d600  pss=1965345  padding=1961920  num_aliases=1
+18)  36658328 (98.0%) r@0x284d600  pss=1965345  padding=1961920  num_aliases=1
              source_path= 	object_path=
              flags={}  name=** merge constants
-19)  36739867 (98.0%) r@0x284e364  pss=3  padding=3  num_aliases=1
+19)  36658331 (98.0%) r@0x284e364  pss=3  padding=3  num_aliases=1
              source_path= 	object_path=
              flags={}  name=** symbol gap 0
-20)  36739875 (98.0%) r@0x284e364  pss=8  padding=0  num_aliases=1
+20)  36658339 (98.0%) r@0x284e364  pss=8  padding=0  num_aliases=1
              source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
-21)  36739919 (98.0%) r@0x284e370  pss=44  padding=4  num_aliases=1
+21)  36658383 (98.0%) r@0x284e370  pss=44  padding=4  num_aliases=1
              source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
              flags={}  name=Name
-22)  36739951 (98.0%) r@0x284e398  pss=32  padding=0  num_aliases=1
+22)  36658415 (98.0%) r@0x284e398  pss=32  padding=0  num_aliases=1
              source_path=third_party/container/container.c 	object_path=third_party/sub/ContiguousContainer.o
              flags={}  name=chrome::mojom::FilePatcher::Name_
-23)  37415991 (99.8%) r@0x28f3450  pss=676040  padding=675992  num_aliases=1
+23)  37334455 (99.8%) r@0x28f3450  pss=676040  padding=675992  num_aliases=1
              source_path=third_party/paint.cc 	object_path=third_party/sub/PaintChunker.o
              flags={anon}  name=kAnimationFrameTimeHistogramClassPath
-24)  37415995 (99.8%) r@0x28f3480  pss=4  padding=0  num_aliases=1
+24)  37334459 (99.8%) r@0x28f3480  pss=4  padding=0  num_aliases=1
              source_path=third_party/paint.cc 	object_path=third_party/sub/PaintChunker.o
              flags={anon}  name=blink::CSSValueKeywordsHash::findValueImpl::value_word_list
                   full_name=blink::CSSValueKeywordsHash::findValueImpl(char const*, unsigned int)::value_word_list
-25)  37416011 (99.8%) t@0x28d900   pss=16  padding=0  num_aliases=1
+25)  37334475 (99.8%) t@0x28d900   pss=16  padding=0  num_aliases=1
              source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
              flags={startup}  name=_GLOBAL__sub_I_page_allocator.cc
-26)  37416067 (99.8%) t@0x28d910   pss=56  padding=0  num_aliases=1
+26)  37334531 (99.8%) t@0x28d910   pss=56  padding=0  num_aliases=1
              source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
              flags={startup}  name=_GLOBAL__sub_I_bbr_sender.cc
-27)  37416095 (99.8%) t@0x28d948   pss=28  padding=0  num_aliases=1
+27)  37334559 (99.8%) t@0x28d948   pss=28  padding=0  num_aliases=1
              source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
              flags={startup}  name=_GLOBAL__sub_I_pacing_sender.cc
-28)  37416133 (99.8%) t@0x28d964   pss=38  padding=0  num_aliases=1
+28)  37334597 (99.8%) t@0x28d964   pss=38  padding=0  num_aliases=1
              source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
              flags={}  name=extFromUUseMapping
                   full_name=extFromUUseMapping(signed char, unsigned int, int)
-29)  37416165 (99.8%) t@0x28d98a   pss=32  padding=0  num_aliases=1
+29)  37334629 (99.8%) t@0x28d98a   pss=32  padding=0  num_aliases=1
              source_path=base/page_allocator.cc 	object_path=base/base/page_allocator.o
              flags={}  name=extFromUUseMapping
                   full_name=extFromUUseMapping(aj, int)
-30)  37425923 (99.8%) t@Group      pss=9758  padding=9758  count=2
+30)  37344387 (99.8%) t@Group      pss=9758  padding=9758  count=2
              source_path= 	object_path=
              flags={}  name=** symbol gaps
 > 0)       5718 (58.6%) t@0x28f000   pss=5718  padding=5718  num_aliases=1
@@ -401,74 +401,74 @@
 > 1)       9758 (100.0%) t@0x2a1000   pss=4040  padding=4040  num_aliases=1
                source_path= 	object_path=
                flags={}  name=** symbol gap 1
-31)  37426371 (99.8%) t@0x28f000   pss=448  padding=0  num_aliases=1
+31)  37344835 (99.8%) t@0x28f000   pss=448  padding=0  num_aliases=1
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={gen}  name=ucnv_extMatchFromU
                   full_name=ucnv_extMatchFromU(int const*, int, unsigned short const*, int, unsigned short const*, int, unsigned int*, signed char, signed char)
-32)  37426399 (99.8%) t@0x28f1c8   pss=28  padding=8  num_aliases=1
+32)  37344863 (99.8%) t@0x28f1c8   pss=28  padding=8  num_aliases=1
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={startup,gen}  name=_GLOBAL__sub_I_SkDeviceProfile.cpp
-33)  37495523 (100.0%) t@0x28f1e0   pss=69124  padding=4  num_aliases=1
+33)  37413987 (100.0%) t@0x28f1e0   pss=69124  padding=4  num_aliases=1
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={unlikely,gen}  name=foo_bar
-34)  37495547 (100.0%) t@0x2a0000   pss=24 (size=48)  padding=32  num_aliases=2
+34)  37414011 (100.0%) t@0x2a0000   pss=24 (size=48)  padding=32  num_aliases=2
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={gen}  name=BazAlias
                   full_name=BazAlias(bool)
-35)  37495571 (100.0%) t@0x2a0000   pss=24 (size=48)  padding=32  num_aliases=2
+35)  37414035 (100.0%) t@0x2a0000   pss=24 (size=48)  padding=32  num_aliases=2
              source_path= 	object_path=
              flags={}  name=blink::ContiguousContainerBase::shrinkToFit
                   full_name=blink::ContiguousContainerBase::shrinkToFit()
-36)  37495574 (100.0%) t@0x2a0010   pss=3 (size=12)  padding=0  num_aliases=4
+36)  37414038 (100.0%) t@0x2a0010   pss=3 (size=12)  padding=0  num_aliases=4
              source_path=third_party/fft_float.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o
              flags={}  name=BarAlias
                   full_name=BarAlias()
-37)  37495577 (100.0%) t@0x2a0010   pss=3 (size=12)  padding=0  num_aliases=4
+37)  37414041 (100.0%) t@0x2a0010   pss=3 (size=12)  padding=0  num_aliases=4
              source_path=third_party/fft_float.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o
              flags={}  name=FooAlias
                   full_name=FooAlias()
-38)  37495580 (100.0%) t@0x2a0010   pss=3 (size=12)  padding=0  num_aliases=4
+38)  37414044 (100.0%) t@0x2a0010   pss=3 (size=12)  padding=0  num_aliases=4
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={gen,clone}  name=blink::ContiguousContainerBase::shrinkToFit
                   full_name=blink::ContiguousContainerBase::shrinkToFit()
-39)  37495583 (100.0%) t@0x2a0010   pss=3 (size=12)  padding=0  num_aliases=4
+39)  37414047 (100.0%) t@0x2a0010   pss=3 (size=12)  padding=0  num_aliases=4
              source_path=third_party/paint.cc 	object_path=third_party/sub/PaintChunker.o
              flags={clone}  name=blink::ContiguousContainerBase::shrinkToFit
                   full_name=blink::ContiguousContainerBase::shrinkToFit()
-40)  37495611 (100.0%) t@0x2a0020   pss=28  padding=4  num_aliases=1
+40)  37414075 (100.0%) t@0x2a0020   pss=28  padding=4  num_aliases=1
              source_path=third_party/container/container.c 	object_path=third_party/sub/ContiguousContainer.o
              flags={}  name=blink::ContiguousContainerBase::ContiguousContainerBase
                   full_name=blink::ContiguousContainerBase::ContiguousContainerBase(blink::ContiguousContainerBase&&)
-41)  37495705 (100.0%) t@0x2a1000   pss=94  padding=0  num_aliases=1
+41)  37414169 (100.0%) t@0x2a1000   pss=94  padding=0  num_aliases=1
              source_path=third_party/container/container.c 	object_path=third_party/sub/ContiguousContainer.o
              flags={anon,clone}  name=blink::PaintChunker::releasePaintChunks
                   full_name=blink::PaintChunker::releasePaintChunks()
-42)  37499739 (100.0%) t@0x2a2000   pss=4034  padding=4002  num_aliases=1
+42)  37418203 (100.0%) t@0x2a2000   pss=4034  padding=4002  num_aliases=1
              source_path=third_party/container/container.c 	object_path=third_party/sub/ContiguousContainer.o
              flags={}  name=** outlined function
-43)  37499763 (100.0%) t@0x2a2020   pss=24 (size=48)  padding=0  num_aliases=2
+43)  37418227 (100.0%) t@0x2a2020   pss=24 (size=48)  padding=0  num_aliases=2
              source_path= 	object_path=
              flags={}  name=** outlined function * 2
-44)  37499787 (100.0%) t@0x2a2020   pss=24 (size=48)  padding=0  num_aliases=2
+44)  37418251 (100.0%) t@0x2a2020   pss=24 (size=48)  padding=0  num_aliases=2
              source_path= 	object_path=
              flags={}  name=aliasedWithOutlinedFunction
                   full_name=aliasedWithOutlinedFunction()
-45)  37499787 (100.0%) b@0x0        pss=262144  padding=0  num_aliases=1
+45)  37418251 (100.0%) b@0x0        pss=262144  padding=0  num_aliases=1
              source_path=third_party/fft_float.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o
              flags={}  name=ff_cos_131072
-46)  37499787 (100.0%) b@0x0        pss=131072  padding=0  num_aliases=1
+46)  37418251 (100.0%) b@0x0        pss=131072  padding=0  num_aliases=1
              source_path=third_party/fft_fixed.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_fixed.o
              flags={}  name=ff_cos_131072_fixed
-47)  37499787 (100.0%) b@0x0        pss=131072  padding=0  num_aliases=1
+47)  37418251 (100.0%) b@0x0        pss=131072  padding=0  num_aliases=1
              source_path=third_party/fft_float.cc 	object_path=third_party/ffmpeg/libffmpeg_internal.a/fft_float.o
              flags={}  name=ff_cos_65536
-48)  37499787 (100.0%) b@0x2dffda0  pss=28  padding=0  num_aliases=1
+48)  37418251 (100.0%) b@0x2dffda0  pss=28  padding=0  num_aliases=1
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={gen}  name=g_chrome_content_browser_client
-49)  37499787 (100.0%) b@0x2dffe80  pss=200  padding=196  num_aliases=1
+49)  37418251 (100.0%) b@0x2dffe80  pss=200  padding=196  num_aliases=1
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={gen}  name=SaveHistogram::atomic_histogram_pointer
                   full_name=SaveHistogram(_JNIEnv*, base::android::JavaParamRef<_jobject*> const&, base::android::JavaParamRef<_jstring*> const&, base::android::JavaParamRef<_jlongArray*> const&, int)::atomic_histogram_pointer
-50)  37499787 (100.0%) b@0x2dffe84  pss=4  padding=0  num_aliases=1
+50)  37418251 (100.0%) b@0x2dffe84  pss=4  padding=0  num_aliases=1
              source_path=third_party/icu/ucnv_ext.c 	object_path=third_party/icu/icuuc/ucnv_ext.o
              flags={anon,gen}  name=g_AnimationFrameTimeHistogram_clazz
diff --git a/tools/binary_size/libsupersize/testdata/SymbolGroupMethods.golden b/tools/binary_size/libsupersize/testdata/SymbolGroupMethods.golden
index ae370478..ebbcc05 100644
--- a/tools/binary_size/libsupersize/testdata/SymbolGroupMethods.golden
+++ b/tools/binary_size/libsupersize/testdata/SymbolGroupMethods.golden
@@ -1,10 +1,10 @@
 GroupedByName()
-Showing 47 symbols (47 unique) with total pss: 37499787 bytes
+Showing 47 symbols (47 unique) with total pss: 37418251 bytes
 Histogram of symbols based on PSS:
       {0}: 6    [8,16): 3     [64,128): 2      [2048,4096): 1      [524288,1048576): 2
     [2,4): 3   [16,32): 11   [128,256): 1     [8192,16384): 1     [1048576,2097152): 1
     [4,8): 6   [32,64): 7    [256,512): 1   [65536,131072): 1   [33554432,67108864): 1
-Sizes: .text=81.8kb     .rodata=2.52mb     .data.rel.ro=92 bytes   .data=168 bytes  .bss=512kb      .other=32.4mb     total=35.8mb
+Sizes: .text=81.8kb     .rodata=2.52mb     .data.rel.ro=92 bytes   .data=168 bytes  .bss=512kb      .other=32.3mb     total=35.7mb
 Counts: .text=21 .rodata=11 .data.rel.ro=3 .data=5 .bss=6 .other=1
 Number of unique paths: 9
 
@@ -24,47 +24,47 @@
 10)    790244 (2.1%)  *@Group      789904          chrome::mojom::FieldTrialRecorderProxy [vtable] (count=1)
 11)    790276 (2.1%)  *@Group      32              .Lswitch.table.45 (count=1)
 12)    790284 (2.1%)  *@Group      8               kSystemClassPrefixes (count=1)
-13)  34774455 (92.7%) *@Group      33984171        Overhead: ELF file (count=1)
-14)  34774460 (92.7%) *@Group      5               "Str1" (count=2)
-15)  34774476 (92.7%) *@Group      16              "String literal2" (count=1)
-16)  34774519 (92.7%) *@Group      43              ** merge strings (count=1)
-17)  36739864 (98.0%) *@Group      1965345         ** merge constants (count=1)
-18)  36739867 (98.0%) *@Group      3               ** symbol gap 0 (count=1)
-19)  36739875 (98.0%) *@Group      8                (count=1)
-20)  36739919 (98.0%) *@Group      44              Name (count=1)
-21)  36739951 (98.0%) *@Group      32              chrome::mojom::FilePatcher::Name_ (count=1)
-22)  37415991 (99.8%) *@Group      676040          kAnimationFrameTimeHistogramClassPath (count=1)
-23)  37415995 (99.8%) *@Group      4               blink::CSSValueKeywordsHash::findValueImpl::value_word_list (count=1)
-24)  37416011 (99.8%) *@Group      16              _GLOBAL__sub_I_page_allocator.cc (count=1)
-25)  37416067 (99.8%) *@Group      56              _GLOBAL__sub_I_bbr_sender.cc (count=1)
-26)  37416095 (99.8%) *@Group      28              _GLOBAL__sub_I_pacing_sender.cc (count=1)
-27)  37416165 (99.8%) *@Group      70              extFromUUseMapping (count=2)
-28)  37425923 (99.8%) *@Group      9758            ** symbol gaps (count=1)
-29)  37426371 (99.8%) *@Group      448             ucnv_extMatchFromU (count=1)
-30)  37426399 (99.8%) *@Group      28              _GLOBAL__sub_I_SkDeviceProfile.cpp (count=1)
-31)  37495523 (100.0%) *@Group      69124           foo_bar (count=1)
-32)  37495547 (100.0%) *@Group      24              BazAlias (count=1)
-33)  37495577 (100.0%) *@Group      30              blink::ContiguousContainerBase::shrinkToFit (count=3)
-34)  37495580 (100.0%) *@Group      3               BarAlias (count=1)
-35)  37495583 (100.0%) *@Group      3               FooAlias (count=1)
-36)  37495611 (100.0%) *@Group      28              blink::ContiguousContainerBase::ContiguousContainerBase (count=1)
-37)  37495705 (100.0%) *@Group      94              blink::PaintChunker::releasePaintChunks (count=1)
-38)  37499739 (100.0%) *@Group      4034            ** outlined function (count=1)
-39)  37499763 (100.0%) *@Group      24              ** outlined function * 2 (count=1)
-40)  37499787 (100.0%) *@Group      24              aliasedWithOutlinedFunction (count=1)
-41)  37499787 (100.0%) *@Group      0               ff_cos_131072 (count=1)
-42)  37499787 (100.0%) *@Group      0               ff_cos_131072_fixed (count=1)
-43)  37499787 (100.0%) *@Group      0               ff_cos_65536 (count=1)
-44)  37499787 (100.0%) *@Group      0               g_chrome_content_browser_client (count=1)
-45)  37499787 (100.0%) *@Group      0               SaveHistogram::atomic_histogram_pointer (count=1)
-46)  37499787 (100.0%) *@Group      0               g_AnimationFrameTimeHistogram_clazz (count=1)
+13)  34692919 (92.7%) *@Group      33902635        Overhead: ELF file (count=1)
+14)  34692924 (92.7%) *@Group      5               "Str1" (count=2)
+15)  34692940 (92.7%) *@Group      16              "String literal2" (count=1)
+16)  34692983 (92.7%) *@Group      43              ** merge strings (count=1)
+17)  36658328 (98.0%) *@Group      1965345         ** merge constants (count=1)
+18)  36658331 (98.0%) *@Group      3               ** symbol gap 0 (count=1)
+19)  36658339 (98.0%) *@Group      8                (count=1)
+20)  36658383 (98.0%) *@Group      44              Name (count=1)
+21)  36658415 (98.0%) *@Group      32              chrome::mojom::FilePatcher::Name_ (count=1)
+22)  37334455 (99.8%) *@Group      676040          kAnimationFrameTimeHistogramClassPath (count=1)
+23)  37334459 (99.8%) *@Group      4               blink::CSSValueKeywordsHash::findValueImpl::value_word_list (count=1)
+24)  37334475 (99.8%) *@Group      16              _GLOBAL__sub_I_page_allocator.cc (count=1)
+25)  37334531 (99.8%) *@Group      56              _GLOBAL__sub_I_bbr_sender.cc (count=1)
+26)  37334559 (99.8%) *@Group      28              _GLOBAL__sub_I_pacing_sender.cc (count=1)
+27)  37334629 (99.8%) *@Group      70              extFromUUseMapping (count=2)
+28)  37344387 (99.8%) *@Group      9758            ** symbol gaps (count=1)
+29)  37344835 (99.8%) *@Group      448             ucnv_extMatchFromU (count=1)
+30)  37344863 (99.8%) *@Group      28              _GLOBAL__sub_I_SkDeviceProfile.cpp (count=1)
+31)  37413987 (100.0%) *@Group      69124           foo_bar (count=1)
+32)  37414011 (100.0%) *@Group      24              BazAlias (count=1)
+33)  37414041 (100.0%) *@Group      30              blink::ContiguousContainerBase::shrinkToFit (count=3)
+34)  37414044 (100.0%) *@Group      3               BarAlias (count=1)
+35)  37414047 (100.0%) *@Group      3               FooAlias (count=1)
+36)  37414075 (100.0%) *@Group      28              blink::ContiguousContainerBase::ContiguousContainerBase (count=1)
+37)  37414169 (100.0%) *@Group      94              blink::PaintChunker::releasePaintChunks (count=1)
+38)  37418203 (100.0%) *@Group      4034            ** outlined function (count=1)
+39)  37418227 (100.0%) *@Group      24              ** outlined function * 2 (count=1)
+40)  37418251 (100.0%) *@Group      24              aliasedWithOutlinedFunction (count=1)
+41)  37418251 (100.0%) *@Group      0               ff_cos_131072 (count=1)
+42)  37418251 (100.0%) *@Group      0               ff_cos_131072_fixed (count=1)
+43)  37418251 (100.0%) *@Group      0               ff_cos_65536 (count=1)
+44)  37418251 (100.0%) *@Group      0               g_chrome_content_browser_client (count=1)
+45)  37418251 (100.0%) *@Group      0               SaveHistogram::atomic_histogram_pointer (count=1)
+46)  37418251 (100.0%) *@Group      0               g_AnimationFrameTimeHistogram_clazz (count=1)
 GroupedByName(depth=1)
-Showing 39 symbols (39 unique) with total pss: 37499787 bytes
+Showing 39 symbols (39 unique) with total pss: 37418251 bytes
 Histogram of symbols based on PSS:
       {0}: 6    [8,16): 4    [64,128): 1      [2048,4096): 1      [524288,1048576): 2
     [2,4): 3   [16,32): 8   [128,256): 2     [8192,16384): 1     [1048576,2097152): 1
     [4,8): 1   [32,64): 6   [256,512): 1   [65536,131072): 1   [33554432,67108864): 1
-Sizes: .text=81.8kb     .rodata=2.52mb     .data.rel.ro=92 bytes   .data=168 bytes  .bss=512kb      .other=32.4mb     total=35.8mb
+Sizes: .text=81.8kb     .rodata=2.52mb     .data.rel.ro=92 bytes   .data=168 bytes  .bss=512kb      .other=32.3mb     total=35.7mb
 Counts: .text=21 .rodata=11 .data.rel.ro=3 .data=5 .bss=6 .other=1
 Number of unique paths: 9
 
@@ -80,43 +80,43 @@
 6)     790276 (2.1%)  *@Group      789960          chrome (count=3)
 7)     790308 (2.1%)  *@Group      32              .Lswitch.table.45 (count=1)
 8)     790316 (2.1%)  *@Group      8               kSystemClassPrefixes (count=1)
-9)   34774487 (92.7%) *@Group      33984171        Overhead: ELF file (count=1)
-10)  34774492 (92.7%) *@Group      5               "Str1" (count=2)
-11)  34774508 (92.7%) *@Group      16              "String literal2" (count=1)
-12)  34774551 (92.7%) *@Group      43              ** merge strings (count=1)
-13)  36739896 (98.0%) *@Group      1965345         ** merge constants (count=1)
-14)  36739899 (98.0%) *@Group      3               ** symbol gap 0 (count=1)
-15)  36739907 (98.0%) *@Group      8                (count=1)
-16)  36739951 (98.0%) *@Group      44              Name (count=1)
-17)  37415991 (99.8%) *@Group      676040          kAnimationFrameTimeHistogramClassPath (count=1)
-18)  37416147 (99.8%) *@Group      156             blink (count=6)
-19)  37416163 (99.8%) *@Group      16              _GLOBAL__sub_I_page_allocator.cc (count=1)
-20)  37416219 (99.8%) *@Group      56              _GLOBAL__sub_I_bbr_sender.cc (count=1)
-21)  37416247 (99.8%) *@Group      28              _GLOBAL__sub_I_pacing_sender.cc (count=1)
-22)  37416317 (99.8%) *@Group      70              extFromUUseMapping (count=2)
-23)  37426075 (99.8%) *@Group      9758            ** symbol gaps (count=1)
-24)  37426523 (99.8%) *@Group      448             ucnv_extMatchFromU (count=1)
-25)  37426551 (99.8%) *@Group      28              _GLOBAL__sub_I_SkDeviceProfile.cpp (count=1)
-26)  37495675 (100.0%) *@Group      69124           foo_bar (count=1)
-27)  37495699 (100.0%) *@Group      24              BazAlias (count=1)
-28)  37495702 (100.0%) *@Group      3               BarAlias (count=1)
-29)  37495705 (100.0%) *@Group      3               FooAlias (count=1)
-30)  37499739 (100.0%) *@Group      4034            ** outlined function (count=1)
-31)  37499763 (100.0%) *@Group      24              ** outlined function * 2 (count=1)
-32)  37499787 (100.0%) *@Group      24              aliasedWithOutlinedFunction (count=1)
-33)  37499787 (100.0%) *@Group      0               ff_cos_131072 (count=1)
-34)  37499787 (100.0%) *@Group      0               ff_cos_131072_fixed (count=1)
-35)  37499787 (100.0%) *@Group      0               ff_cos_65536 (count=1)
-36)  37499787 (100.0%) *@Group      0               g_chrome_content_browser_client (count=1)
-37)  37499787 (100.0%) *@Group      0               SaveHistogram (count=1)
-38)  37499787 (100.0%) *@Group      0               g_AnimationFrameTimeHistogram_clazz (count=1)
+9)   34692951 (92.7%) *@Group      33902635        Overhead: ELF file (count=1)
+10)  34692956 (92.7%) *@Group      5               "Str1" (count=2)
+11)  34692972 (92.7%) *@Group      16              "String literal2" (count=1)
+12)  34693015 (92.7%) *@Group      43              ** merge strings (count=1)
+13)  36658360 (98.0%) *@Group      1965345         ** merge constants (count=1)
+14)  36658363 (98.0%) *@Group      3               ** symbol gap 0 (count=1)
+15)  36658371 (98.0%) *@Group      8                (count=1)
+16)  36658415 (98.0%) *@Group      44              Name (count=1)
+17)  37334455 (99.8%) *@Group      676040          kAnimationFrameTimeHistogramClassPath (count=1)
+18)  37334611 (99.8%) *@Group      156             blink (count=6)
+19)  37334627 (99.8%) *@Group      16              _GLOBAL__sub_I_page_allocator.cc (count=1)
+20)  37334683 (99.8%) *@Group      56              _GLOBAL__sub_I_bbr_sender.cc (count=1)
+21)  37334711 (99.8%) *@Group      28              _GLOBAL__sub_I_pacing_sender.cc (count=1)
+22)  37334781 (99.8%) *@Group      70              extFromUUseMapping (count=2)
+23)  37344539 (99.8%) *@Group      9758            ** symbol gaps (count=1)
+24)  37344987 (99.8%) *@Group      448             ucnv_extMatchFromU (count=1)
+25)  37345015 (99.8%) *@Group      28              _GLOBAL__sub_I_SkDeviceProfile.cpp (count=1)
+26)  37414139 (100.0%) *@Group      69124           foo_bar (count=1)
+27)  37414163 (100.0%) *@Group      24              BazAlias (count=1)
+28)  37414166 (100.0%) *@Group      3               BarAlias (count=1)
+29)  37414169 (100.0%) *@Group      3               FooAlias (count=1)
+30)  37418203 (100.0%) *@Group      4034            ** outlined function (count=1)
+31)  37418227 (100.0%) *@Group      24              ** outlined function * 2 (count=1)
+32)  37418251 (100.0%) *@Group      24              aliasedWithOutlinedFunction (count=1)
+33)  37418251 (100.0%) *@Group      0               ff_cos_131072 (count=1)
+34)  37418251 (100.0%) *@Group      0               ff_cos_131072_fixed (count=1)
+35)  37418251 (100.0%) *@Group      0               ff_cos_65536 (count=1)
+36)  37418251 (100.0%) *@Group      0               g_chrome_content_browser_client (count=1)
+37)  37418251 (100.0%) *@Group      0               SaveHistogram (count=1)
+38)  37418251 (100.0%) *@Group      0               g_AnimationFrameTimeHistogram_clazz (count=1)
 GroupedByName(depth=-1)
-Showing 42 symbols (42 unique) with total pss: 37499787 bytes
+Showing 42 symbols (42 unique) with total pss: 37418251 bytes
 Histogram of symbols based on PSS:
       {0}: 6    [8,16): 4    [64,128): 2      [2048,4096): 1      [524288,1048576): 2
     [2,4): 3   [16,32): 8   [128,256): 1     [8192,16384): 1     [1048576,2097152): 1
     [4,8): 2   [32,64): 8   [256,512): 1   [65536,131072): 1   [33554432,67108864): 1
-Sizes: .text=81.8kb     .rodata=2.52mb     .data.rel.ro=92 bytes   .data=168 bytes  .bss=512kb      .other=32.4mb     total=35.8mb
+Sizes: .text=81.8kb     .rodata=2.52mb     .data.rel.ro=92 bytes   .data=168 bytes  .bss=512kb      .other=32.3mb     total=35.7mb
 Counts: .text=21 .rodata=11 .data.rel.ro=3 .data=5 .bss=6 .other=1
 Number of unique paths: 9
 
@@ -132,46 +132,46 @@
 6)     790244 (2.1%)  *@Group      789928          chrome::mojom (count=2)
 7)     790276 (2.1%)  *@Group      32              .Lswitch.table.45 (count=1)
 8)     790284 (2.1%)  *@Group      8               kSystemClassPrefixes (count=1)
-9)   34774455 (92.7%) *@Group      33984171        Overhead: ELF file (count=1)
-10)  34774460 (92.7%) *@Group      5               "Str1" (count=2)
-11)  34774476 (92.7%) *@Group      16              "String literal2" (count=1)
-12)  34774519 (92.7%) *@Group      43              ** merge strings (count=1)
-13)  36739864 (98.0%) *@Group      1965345         ** merge constants (count=1)
-14)  36739867 (98.0%) *@Group      3               ** symbol gap 0 (count=1)
-15)  36739875 (98.0%) *@Group      8                (count=1)
-16)  36739919 (98.0%) *@Group      44              Name (count=1)
-17)  36739951 (98.0%) *@Group      32              chrome::mojom::FilePatcher (count=1)
-18)  37415991 (99.8%) *@Group      676040          kAnimationFrameTimeHistogramClassPath (count=1)
-19)  37415995 (99.8%) *@Group      4               blink::CSSValueKeywordsHash::findValueImpl (count=1)
-20)  37416011 (99.8%) *@Group      16              _GLOBAL__sub_I_page_allocator.cc (count=1)
-21)  37416067 (99.8%) *@Group      56              _GLOBAL__sub_I_bbr_sender.cc (count=1)
-22)  37416095 (99.8%) *@Group      28              _GLOBAL__sub_I_pacing_sender.cc (count=1)
-23)  37416165 (99.8%) *@Group      70              extFromUUseMapping (count=2)
-24)  37425923 (99.8%) *@Group      9758            ** symbol gaps (count=1)
-25)  37426371 (99.8%) *@Group      448             ucnv_extMatchFromU (count=1)
-26)  37426399 (99.8%) *@Group      28              _GLOBAL__sub_I_SkDeviceProfile.cpp (count=1)
-27)  37495523 (100.0%) *@Group      69124           foo_bar (count=1)
-28)  37495547 (100.0%) *@Group      24              BazAlias (count=1)
-29)  37495605 (100.0%) *@Group      58              blink::ContiguousContainerBase (count=4)
-30)  37495608 (100.0%) *@Group      3               BarAlias (count=1)
-31)  37495611 (100.0%) *@Group      3               FooAlias (count=1)
-32)  37495705 (100.0%) *@Group      94              blink::PaintChunker (count=1)
-33)  37499739 (100.0%) *@Group      4034            ** outlined function (count=1)
-34)  37499763 (100.0%) *@Group      24              ** outlined function * 2 (count=1)
-35)  37499787 (100.0%) *@Group      24              aliasedWithOutlinedFunction (count=1)
-36)  37499787 (100.0%) *@Group      0               ff_cos_131072 (count=1)
-37)  37499787 (100.0%) *@Group      0               ff_cos_131072_fixed (count=1)
-38)  37499787 (100.0%) *@Group      0               ff_cos_65536 (count=1)
-39)  37499787 (100.0%) *@Group      0               g_chrome_content_browser_client (count=1)
-40)  37499787 (100.0%) *@Group      0               SaveHistogram (count=1)
-41)  37499787 (100.0%) *@Group      0               g_AnimationFrameTimeHistogram_clazz (count=1)
+9)   34692919 (92.7%) *@Group      33902635        Overhead: ELF file (count=1)
+10)  34692924 (92.7%) *@Group      5               "Str1" (count=2)
+11)  34692940 (92.7%) *@Group      16              "String literal2" (count=1)
+12)  34692983 (92.7%) *@Group      43              ** merge strings (count=1)
+13)  36658328 (98.0%) *@Group      1965345         ** merge constants (count=1)
+14)  36658331 (98.0%) *@Group      3               ** symbol gap 0 (count=1)
+15)  36658339 (98.0%) *@Group      8                (count=1)
+16)  36658383 (98.0%) *@Group      44              Name (count=1)
+17)  36658415 (98.0%) *@Group      32              chrome::mojom::FilePatcher (count=1)
+18)  37334455 (99.8%) *@Group      676040          kAnimationFrameTimeHistogramClassPath (count=1)
+19)  37334459 (99.8%) *@Group      4               blink::CSSValueKeywordsHash::findValueImpl (count=1)
+20)  37334475 (99.8%) *@Group      16              _GLOBAL__sub_I_page_allocator.cc (count=1)
+21)  37334531 (99.8%) *@Group      56              _GLOBAL__sub_I_bbr_sender.cc (count=1)
+22)  37334559 (99.8%) *@Group      28              _GLOBAL__sub_I_pacing_sender.cc (count=1)
+23)  37334629 (99.8%) *@Group      70              extFromUUseMapping (count=2)
+24)  37344387 (99.8%) *@Group      9758            ** symbol gaps (count=1)
+25)  37344835 (99.8%) *@Group      448             ucnv_extMatchFromU (count=1)
+26)  37344863 (99.8%) *@Group      28              _GLOBAL__sub_I_SkDeviceProfile.cpp (count=1)
+27)  37413987 (100.0%) *@Group      69124           foo_bar (count=1)
+28)  37414011 (100.0%) *@Group      24              BazAlias (count=1)
+29)  37414069 (100.0%) *@Group      58              blink::ContiguousContainerBase (count=4)
+30)  37414072 (100.0%) *@Group      3               BarAlias (count=1)
+31)  37414075 (100.0%) *@Group      3               FooAlias (count=1)
+32)  37414169 (100.0%) *@Group      94              blink::PaintChunker (count=1)
+33)  37418203 (100.0%) *@Group      4034            ** outlined function (count=1)
+34)  37418227 (100.0%) *@Group      24              ** outlined function * 2 (count=1)
+35)  37418251 (100.0%) *@Group      24              aliasedWithOutlinedFunction (count=1)
+36)  37418251 (100.0%) *@Group      0               ff_cos_131072 (count=1)
+37)  37418251 (100.0%) *@Group      0               ff_cos_131072_fixed (count=1)
+38)  37418251 (100.0%) *@Group      0               ff_cos_65536 (count=1)
+39)  37418251 (100.0%) *@Group      0               g_chrome_content_browser_client (count=1)
+40)  37418251 (100.0%) *@Group      0               SaveHistogram (count=1)
+41)  37418251 (100.0%) *@Group      0               g_AnimationFrameTimeHistogram_clazz (count=1)
 GroupedByName(depth=1, min_count=2)
-Showing 39 symbols (37 unique) with total pss: 37499787 bytes
+Showing 39 symbols (37 unique) with total pss: 37418251 bytes
 Histogram of symbols based on PSS:
      [2,4): 3    [16,32): 9     [128,256): 3      [8192,16384): 1     [262144,524288): 1   [33554432,67108864): 1
      [4,8): 2    [32,64): 6     [256,512): 1    [65536,131072): 1    [524288,1048576): 2
     [8,16): 4   [64,128): 1   [2048,4096): 1   [131072,262144): 2   [1048576,2097152): 1
-Sizes: .text=81.8kb     .rodata=2.52mb     .data.rel.ro=92 bytes   .data=168 bytes  .bss=512kb      .other=32.4mb     total=35.8mb
+Sizes: .text=81.8kb     .rodata=2.52mb     .data.rel.ro=92 bytes   .data=168 bytes  .bss=512kb      .other=32.3mb     total=35.7mb
 Counts: .text=21 .rodata=11 .data.rel.ro=3 .data=5 .bss=6 .other=1
 Number of unique paths: 9
 
@@ -196,62 +196,62 @@
              .Lswitch.table.45
 8)     790316 (2.1%)  R@0x2cd84f0  8              third_party/gvr-android-sdk/libgvr_shim_static_arm.a/libport_android_jni.a_jni_utils.o
              kSystemClassPrefixes
-9)   34774487 (92.7%) o@0x0        33984171       {no path}
+9)   34692951 (92.7%) o@0x0        33902635       {no path}
              Overhead: ELF file
-10)  34774492 (92.7%) *@Group      5              {no path}
+10)  34692956 (92.7%) *@Group      5              {no path}
              "Str1" (count=2)
-11)  34774508 (92.7%) r@0x266e605  16             $root_gen_dir/third_party/icu/ucnv_ext.c
+11)  34692972 (92.7%) r@0x266e605  16             $root_gen_dir/third_party/icu/ucnv_ext.c
              "String literal2"
-12)  34774551 (92.7%) r@0x266e630  43             {no path}
+12)  34693015 (92.7%) r@0x266e630  43             {no path}
              ** merge strings
-13)  36739896 (98.0%) r@0x284d600  1965345        {no path}
+13)  36658360 (98.0%) r@0x284d600  1965345        {no path}
              ** merge constants
-14)  36739899 (98.0%) r@0x284e364  3              {no path}
+14)  36658363 (98.0%) r@0x284e364  3              {no path}
              ** symbol gap 0
-15)  36739907 (98.0%) r@0x284e364  8              base/page_allocator.cc
-16)  36739951 (98.0%) r@0x284e370  44             base/page_allocator.cc
+15)  36658371 (98.0%) r@0x284e364  8              base/page_allocator.cc
+16)  36658415 (98.0%) r@0x284e370  44             base/page_allocator.cc
              Name
-17)  37415991 (99.8%) r@0x28f3450  676040         third_party/paint.cc
+17)  37334455 (99.8%) r@0x28f3450  676040         third_party/paint.cc
              kAnimationFrameTimeHistogramClassPath
-18)  37416147 (99.8%) *@Group      156            {no path}
+18)  37334611 (99.8%) *@Group      156            {no path}
              blink (count=6)
-19)  37416163 (99.8%) t@0x28d900   16             base/page_allocator.cc
+19)  37334627 (99.8%) t@0x28d900   16             base/page_allocator.cc
              _GLOBAL__sub_I_page_allocator.cc
-20)  37416219 (99.8%) t@0x28d910   56             base/page_allocator.cc
+20)  37334683 (99.8%) t@0x28d910   56             base/page_allocator.cc
              _GLOBAL__sub_I_bbr_sender.cc
-21)  37416247 (99.8%) t@0x28d948   28             base/page_allocator.cc
+21)  37334711 (99.8%) t@0x28d948   28             base/page_allocator.cc
              _GLOBAL__sub_I_pacing_sender.cc
-22)  37416317 (99.8%) *@Group      70             base/page_allocator.cc
+22)  37334781 (99.8%) *@Group      70             base/page_allocator.cc
              extFromUUseMapping (count=2)
-23)  37426075 (99.8%) t@Group      9758           {no path}
+23)  37344539 (99.8%) t@Group      9758           {no path}
              ** symbol gaps (count=2)
-24)  37426523 (99.8%) t@0x28f000   448            $root_gen_dir/third_party/icu/ucnv_ext.c
+24)  37344987 (99.8%) t@0x28f000   448            $root_gen_dir/third_party/icu/ucnv_ext.c
              ucnv_extMatchFromU
-25)  37426551 (99.8%) t@0x28f1c8   28             $root_gen_dir/third_party/icu/ucnv_ext.c
+25)  37345015 (99.8%) t@0x28f1c8   28             $root_gen_dir/third_party/icu/ucnv_ext.c
              _GLOBAL__sub_I_SkDeviceProfile.cpp
-26)  37495675 (100.0%) t@0x28f1e0   69124          $root_gen_dir/third_party/icu/ucnv_ext.c
+26)  37414139 (100.0%) t@0x28f1e0   69124          $root_gen_dir/third_party/icu/ucnv_ext.c
              foo_bar
-27)  37495699 (100.0%) t@0x2a0000   24 (size=48)   $root_gen_dir/third_party/icu/ucnv_ext.c
+27)  37414163 (100.0%) t@0x2a0000   24 (size=48)   $root_gen_dir/third_party/icu/ucnv_ext.c
              BazAlias (num_aliases=2)
-28)  37495702 (100.0%) t@0x2a0010   3 (size=12)    third_party/fft_float.cc
+28)  37414166 (100.0%) t@0x2a0010   3 (size=12)    third_party/fft_float.cc
              BarAlias (num_aliases=4)
-29)  37495705 (100.0%) t@0x2a0010   3 (size=12)    third_party/fft_float.cc
+29)  37414169 (100.0%) t@0x2a0010   3 (size=12)    third_party/fft_float.cc
              FooAlias (num_aliases=4)
-30)  37499739 (100.0%) t@0x2a2000   4034           third_party/container/container.c
+30)  37418203 (100.0%) t@0x2a2000   4034           third_party/container/container.c
              ** outlined function
-31)  37499763 (100.0%) t@0x2a2020   24 (size=48)   {no path}
+31)  37418227 (100.0%) t@0x2a2020   24 (size=48)   {no path}
              ** outlined function * 2 (num_aliases=2)
-32)  37499787 (100.0%) t@0x2a2020   24 (size=48)   {no path}
+32)  37418251 (100.0%) t@0x2a2020   24 (size=48)   {no path}
              aliasedWithOutlinedFunction (num_aliases=2)
-33)  37499787 (100.0%) b@0x0        262144         third_party/fft_float.cc
+33)  37418251 (100.0%) b@0x0        262144         third_party/fft_float.cc
              ff_cos_131072
-34)  37499787 (100.0%) b@0x0        131072         third_party/fft_fixed.cc
+34)  37418251 (100.0%) b@0x0        131072         third_party/fft_fixed.cc
              ff_cos_131072_fixed
-35)  37499787 (100.0%) b@0x0        131072         third_party/fft_float.cc
+35)  37418251 (100.0%) b@0x0        131072         third_party/fft_float.cc
              ff_cos_65536
-36)  37499787 (100.0%) b@0x2dffda0  28             $root_gen_dir/third_party/icu/ucnv_ext.c
+36)  37418251 (100.0%) b@0x2dffda0  28             $root_gen_dir/third_party/icu/ucnv_ext.c
              g_chrome_content_browser_client
-37)  37499787 (100.0%) b@0x2dffe80  200            $root_gen_dir/third_party/icu/ucnv_ext.c
+37)  37418251 (100.0%) b@0x2dffe80  200            $root_gen_dir/third_party/icu/ucnv_ext.c
              SaveHistogram::atomic_histogram_pointer
-38)  37499787 (100.0%) b@0x2dffe84  4              $root_gen_dir/third_party/icu/ucnv_ext.c
+38)  37418251 (100.0%) b@0x2dffe84  4              $root_gen_dir/third_party/icu/ucnv_ext.c
              g_AnimationFrameTimeHistogram_clazz
diff --git a/tools/binary_size/libsupersize/testdata/mock_toolchain/mock_readelf.py b/tools/binary_size/libsupersize/testdata/mock_toolchain/mock_readelf.py
index e770cf78..2fb7f78 100644
--- a/tools/binary_size/libsupersize/testdata/mock_toolchain/mock_readelf.py
+++ b/tools/binary_size/libsupersize/testdata/mock_toolchain/mock_readelf.py
@@ -44,23 +44,23 @@
   [ 9] .rel.dyn          REL             00003904 003904 288498 08   A  3   0  4
   [10] .rel.plt          REL             0029fbec 29fbec 000b00 08   A  3   0  4
   [11] .plt              PROGBITS        002a06ec 2a06ec 001094 00  AX  0   0  4
-  [12] .text             PROGBITS       002a1780 2a1780 223cd28 00  AX  0   0 64
+  [12] .text             PROGBITS       0028d900 28d900 2250ba8 00  AX  0   0 64
   [13] .rodata           PROGBITS      0266e5f0 000084 5a72e4 00   A  0   0 256
   [14] .ARM.exidx        ARM_EXIDX      02bd3d10 2bd3d10 1771c8 08  AL 12   0  4
   [15] .ARM.extab        PROGBITS       02bd5858 2bd5858 02cd50 00   A  0   0  4
-  [16] .data.rel.ro.local PROGBITS      02bdac40 2bd9c40 0c0e08 00  WA  0   0 16
-  [17] .data.rel.ro      PROGBITS       02c9d420 2c9c420 104108 00  WA  0   0 16
-  [18] .init_array       INIT_ARRAY     02da4680 2da3680 000008 00  WA  0   0  4
-  [19] .fini_array       FINI_ARRAY     02da4774 2da3774 000008 00  WA  0   0  4
-  [20] .dynamic          DYNAMIC        02da477c 2da377c 000130 08  WA  4   0  4
-  [21] .got              PROGBITS       02da48b4 2da38b4 00a7cc 00  WA  0   0  4
-  [22] .data             PROGBITS       02db0000 2daf000 018d88 00  WA  0   0 32
-  [23] .bss              NOBITS         02dc8220 2dc7220 13d7e8 00  WA  0   0 32
-  [35] .note.gnu.gold-version NOTE     00000000 226c41e8 00001c 00      0   0  4
-  [36] .ARM.attributes  ARM_ATTRIBUTES 00000000 226c4204 00003c 00      0   0  1
-  [37] .symtab           SYMTAB    00000000 226c4240 105ef20 10     38 901679  4
-  [38] .strtab           STRTAB       00000000 23487ea0 213a4fe 00      0   0  1
-  [39] .shstrtab         STRTAB        00000000 25777c2a 0001b4 00      0   0  1
+  [16] .data.rel.ro.local PROGBITS      02c176f0 2c166f0 0c0e08 00  WA  0   0 16
+  [17] .data.rel.ro      PROGBITS       02cd8500 2cd8500 104108 00  WA  0   0 16
+  [18] .init_array       INIT_ARRAY     02ddc608 2ddc608 000008 00  WA  0   0  4
+  [19] .fini_array       FINI_ARRAY     02ddc6f4 2ddc6f4 000008 00  WA  0   0  4
+  [20] .dynamic          DYNAMIC        02ddc6fc 2ddc6fc 000130 08  WA  4   0  4
+  [21] .got              PROGBITS       02ddc834 2ddc834 00a7cc 00  WA  0   0  4
+  [22] .data             PROGBITS       02de7000 2de7000 018d88 00  WA  0   0 32
+  [23] .bss              NOBITS         02dffda0 2dffda0 13d7e8 00  WA  0   0 32
+  [35] .note.gnu.gold-version NOTE     00000000 22700c98 00001c 00      0   0  4
+  [36] .ARM.attributes  ARM_ATTRIBUTES 00000000 22700cb4 00003c 00      0   0  1
+  [37] .symtab           SYMTAB    00000000 22700cf0 105ef20 10     38 901679  4
+  [38] .strtab           STRTAB       00000000 234c4950 213a4fe 00      0   0  1
+  [39] .shstrtab         STRTAB        00000000 257b46da 0001b4 00      0   0  1
 Key to Flags:
   W (write), A (alloc), X (execute), M (merge), S (strings)
   I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
diff --git a/tools/binary_size/libsupersize/testdata/test.map b/tools/binary_size/libsupersize/testdata/test.map
index e9a9c2c..5f05e0d 100644
--- a/tools/binary_size/libsupersize/testdata/test.map
+++ b/tools/binary_size/libsupersize/testdata/test.map
@@ -71,7 +71,7 @@
 .plt            0x0028c864     0x1094
  ** PLT         0x0028c864     0x1094
 
-.text           0x0028d900  0x223cd28
+.text           0x0028d900  0x2250ba8
  .text.startup._GLOBAL__sub_I_page_allocator.cc
                 0x0028d900       0x10 obj/base/base/page_allocator.o
  .text.startup._GLOBAL__sub_I_bbr_sender.cc
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl
index ccbb647..b762a27a 100644
--- a/tools/mb/mb_config.pyl
+++ b/tools/mb/mb_config.pyl
@@ -648,7 +648,6 @@
       # TODO(crbug/597596): Switch this back to debug_trybot when cronet's
       # shared library loading is fixed.
       'android-cronet-arm-dbg': 'android_cronet_debug_static_bot_arm_no_neon',
-      'android-kitkat-arm-coverage-rel': 'android_release_trybot_java_coverage',
       'android-kitkat-arm-rel': 'android_release_trybot',
       'android-marshmallow-arm64-coverage-rel': 'gpu_tests_android_release_trybot_arm64_resource_whitelisting_java_coverage',
       'android-marshmallow-arm64-rel': 'gpu_tests_android_release_trybot_arm64_resource_whitelisting',
@@ -1138,11 +1137,6 @@
       'webview_google',
     ],
 
-    'android_release_trybot_java_coverage': [
-      'android', 'release_trybot', 'strip_debug_info', 'java_coverage',
-      'partial_code_coverage_instrumentation',
-    ],
-
     'android_release_trybot_x86': [
       'android', 'release_trybot', 'strip_debug_info', 'x86',
     ],
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
index 81ecc50..941a22e 100644
--- a/tools/metrics/histograms/enums.xml
+++ b/tools/metrics/histograms/enums.xml
@@ -18122,7 +18122,7 @@
   <int value="602" label="ReportDeviceOsUpdateStatus"/>
   <int value="603" label="DeviceLoginScreenWebUsbAllowDevicesForUrls"/>
   <int value="604" label="AllowSyncXHRInPageDismissal"/>
-  <int value="605" label="DeviceLoginSpokenFeedbackEnabled"/>
+  <int value="605" label="DeviceLoginScreenSpokenFeedbackEnabled"/>
   <int value="606" label="DeviceLoginScreenHighContrastEnabled"/>
   <int value="607" label="DeviceLoginScreenVirtualKeyboardEnabled"/>
   <int value="608" label="CloudExtensionRequestEnabled"/>
@@ -18133,6 +18133,7 @@
   <int value="613" label="DeviceLoginScreenCursorHighlightEnabled"/>
   <int value="614" label="DeviceLoginScreenCaretHighlightEnabled"/>
   <int value="615" label="DeviceLoginScreenMonoAudioEnabled"/>
+  <int value="616" label="TotalMemoryLimitMb"/>
 </enum>
 
 <enum name="EnterprisePolicyInvalidations">
@@ -24750,6 +24751,7 @@
   <int value="3034"
       label="MediaSourceGroupEndTimestampDecreaseWithinMediaSegment"/>
   <int value="3035" label="TextFragmentAnchorTapToDismiss"/>
+  <int value="3036" label="XRIsSessionSupported"/>
 </enum>
 
 <enum name="FeaturePolicyAllowlistType">
@@ -54206,11 +54208,12 @@
 
 <enum name="SecurityLevel">
   <int value="0" label="None"/>
-  <int value="1" label="Non-secure with warning"/>
+  <int value="1" label="HTTP with warning (deprecated)"/>
   <int value="2" label="Secure with EV certificate"/>
   <int value="3" label="Secure"/>
   <int value="4" label="Secure with policy-installed certificate"/>
   <int value="5" label="Dangerous"/>
+  <int value="6" label="Warning"/>
 </enum>
 
 <enum name="SelectFileDialogScope">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index 27a0345..2aca350 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -993,7 +993,8 @@
   <owner>danan@chromium.org</owner>
   <summary>
     Measures the amount of time in milliseconds for users to exit the Add
-    Supervision dialog without enrollment.
+    Supervision dialog without enrollment. This can happen if the user closes
+    the Add Supervision dialog or signs out to switch accounts.
   </summary>
 </histogram>
 
@@ -127449,11 +127450,11 @@
     commit time, for example if the page includes a password field on load
     (which can downgrade the security level). This histogram should be analyzed
     with care because each recorded security level is not necessarily
-    user-visible: in particular, a page may commit as NONE or HTTP_SHOW_WARNING
-    but get quickly downgraded to HTTP_SHOW_WARNING or DANGEROUS, depending on
-    field trial configuration, if it shows a password field on load. Therefore
-    the histogram values should be regarded as an upper-bound on what the user
-    actually sees for the NONE and HTTP_SHOW_WARNING levels.
+    user-visible: in particular, a page may commit as NONE or WARNING but get
+    quickly downgraded to WARNING or DANGEROUS, depending on field trial
+    configuration, if it shows a password field on load. Therefore the histogram
+    values should be regarded as an upper-bound on what the user actually sees
+    for the NONE and WARNING levels.
   </summary>
 </histogram>
 
@@ -175772,12 +175773,14 @@
   <owner>estark@chromium.org</owner>
   <suffix name="DANGEROUS" label="SecurityLevel is DANGEROUS."/>
   <suffix name="EV_SECURE" label="SecurityLevel is EV_SECURE."/>
-  <suffix name="HTTP_SHOW_WARNING" label="SecurityLevel is HTTP_SHOW_WARNING."/>
+  <suffix name="HTTP_SHOW_WARNING"
+      label="SecurityLevel is HTTP_SHOW_WARNING (deprecated)."/>
   <suffix name="NONE" label="SecurityLevel is NONE."/>
   <suffix name="OTHER" label="Unknown SecurityLevel."/>
   <suffix name="SECURE" label="SecurityLevel is SECURE."/>
   <suffix name="SECURE_WITH_POLICY_INSTALLED_CERT"
       label="SecurityLevel is SECURE_WITH_POLICY_INSTALLED_CERT."/>
+  <suffix name="WARNING" label="SecurityLevel is WARNING."/>
   <affected-histogram name="Autofill.SaveCreditCardPrompt.Local"/>
   <affected-histogram name="Autofill.SaveCreditCardPrompt.Upload"/>
   <affected-histogram name="Autofill.UserHappiness.Address"/>
diff --git a/tools/traffic_annotation/summary/annotations.xml b/tools/traffic_annotation/summary/annotations.xml
index a8721be..746578c 100644
--- a/tools/traffic_annotation/summary/annotations.xml
+++ b/tools/traffic_annotation/summary/annotations.xml
@@ -157,6 +157,7 @@
  <item id="network_location_provider" hash_code="23472048" type="1" second_id="96590038" content_hash_code="41087976" os_list="linux,windows" semantics_fields="1" policy_fields="3,4" file_path="services/device/geolocation/network_location_provider.cc"/>
  <item id="network_location_request" hash_code="96590038" type="2" content_hash_code="80741011" os_list="linux,windows" semantics_fields="2,3,4,5" policy_fields="-1" file_path="services/device/geolocation/network_location_request.cc"/>
  <item id="network_time_component" hash_code="46188932" type="0" content_hash_code="28051857" os_list="linux,windows" file_path="components/network_time/network_time_tracker.cc"/>
+ <item id="notification_client" hash_code="78479125" type="0" content_hash_code="61551920" os_list="linux,windows" file_path="remoting/client/notification/notification_client.cc"/>
  <item id="ntp_contextual_suggestions_fetch" hash_code="95711309" type="0" deprecated="2019-04-18" content_hash_code="107035434" file_path=""/>
  <item id="ntp_custom_background" hash_code="92125886" type="0" content_hash_code="61176452" os_list="linux,windows" file_path="chrome/browser/search/instant_service.cc"/>
  <item id="ntp_custom_link_checker_request" hash_code="78408551" type="0" deprecated="2018-10-26" content_hash_code="13407730" file_path=""/>
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
index 62d4125..67105b6 100644
--- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win.cc
@@ -488,15 +488,24 @@
 
   const AXTreeID tree_id = common_anchor->tree()->GetAXTreeID();
   const AXNode::AXID node_id = common_anchor->id();
-  AXPlatformNodeDelegate* delegate = GetDelegate(tree_id, node_id);
-  DCHECK(delegate);
-  while (ui::IsIgnored(delegate->GetData())) {
+  AXPlatformNodeWin* enclosing_node =
+      static_cast<AXPlatformNodeWin*>(AXPlatformNode::FromNativeViewAccessible(
+          GetDelegate(tree_id, node_id)->GetNativeViewAccessible()));
+  DCHECK(enclosing_node);
+  // If this node has an ancestor that is a control type, use that as the
+  // enclosing element.
+  enclosing_node = enclosing_node->GetLowestAccessibleElement();
+  DCHECK(enclosing_node);
+
+  while (ui::IsIgnored(enclosing_node->GetData())) {
     AXPlatformNodeWin* parent = static_cast<AXPlatformNodeWin*>(
-        AXPlatformNode::FromNativeViewAccessible(delegate->GetParent()));
+        AXPlatformNode::FromNativeViewAccessible(enclosing_node->GetParent()));
     DCHECK(parent);
-    delegate = parent->GetDelegate();
+    enclosing_node = parent;
   }
-  delegate->GetNativeViewAccessible()->QueryInterface(IID_PPV_ARGS(element));
+
+  enclosing_node->GetNativeViewAccessible()->QueryInterface(
+      IID_PPV_ARGS(element));
 
   DCHECK(*element);
   return S_OK;
diff --git a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
index 2316b6ac7..a4335a44 100644
--- a/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
+++ b/ui/accessibility/platform/ax_platform_node_textrangeprovider_win_unittest.cc
@@ -2741,28 +2741,109 @@
 
 TEST_F(AXPlatformNodeTextRangeProviderTest,
        TestITextRangeProviderGetEnclosingElement) {
-  Init(BuildTextDocument({"some text", "more text"}));
+  // Set up ax tree with the following structure:
+  //
+  // root
+  // |
+  // paragraph_______
+  // |               |
+  // static_text     link
+  // |               |
+  // text_node       static_text
+  //                 |
+  //                 text_node
+
+  ui::AXNodeData root_data;
+  root_data.id = 1;
+  root_data.role = ax::mojom::Role::kRootWebArea;
+
+  ui::AXNodeData paragraph_data;
+  paragraph_data.id = 2;
+  paragraph_data.role = ax::mojom::Role::kParagraph;
+  root_data.child_ids.push_back(paragraph_data.id);
+
+  ui::AXNodeData static_text_data1;
+  static_text_data1.id = 3;
+  static_text_data1.role = ax::mojom::Role::kStaticText;
+  paragraph_data.child_ids.push_back(static_text_data1.id);
+
+  ui::AXNodeData inline_text_data1;
+  inline_text_data1.id = 4;
+  inline_text_data1.role = ax::mojom::Role::kInlineTextBox;
+  static_text_data1.child_ids.push_back(inline_text_data1.id);
+
+  ui::AXNodeData link_data;
+  link_data.id = 5;
+  link_data.role = ax::mojom::Role::kLink;
+  paragraph_data.child_ids.push_back(link_data.id);
+
+  ui::AXNodeData static_text_data2;
+  static_text_data2.id = 6;
+  static_text_data2.role = ax::mojom::Role::kStaticText;
+  link_data.child_ids.push_back(static_text_data2.id);
+
+  ui::AXNodeData inline_text_data2;
+  inline_text_data2.id = 7;
+  inline_text_data2.role = ax::mojom::Role::kInlineTextBox;
+  static_text_data2.child_ids.push_back(inline_text_data2.id);
+
+  ui::AXTreeUpdate update;
+  ui::AXTreeData tree_data;
+  tree_data.tree_id = ui::AXTreeID::CreateNewAXTreeID();
+  update.tree_data = tree_data;
+  update.has_tree_data = true;
+  update.root_id = root_data.id;
+  update.nodes.push_back(root_data);
+  update.nodes.push_back(paragraph_data);
+  update.nodes.push_back(static_text_data1);
+  update.nodes.push_back(inline_text_data1);
+  update.nodes.push_back(link_data);
+  update.nodes.push_back(static_text_data2);
+  update.nodes.push_back(inline_text_data2);
+
+  Init(update);
+
+  // Set up variables from the tree for testing.
+  AXNode* paragraph_node = GetRootNode()->children()[0];
   AXNodePosition::SetTree(tree_.get());
-  AXNode* root_node = GetRootNode();
+  AXNode* static_text_node1 = paragraph_node->children()[0];
+  AXNode* link_node = paragraph_node->children()[1];
+  AXNode* inline_text_node1 = static_text_node1->children()[0];
+  AXNode* static_text_node2 = link_node->children()[0];
+  AXNode* inline_text_node2 = static_text_node2->children()[0];
 
-  // Test GetEnclosingElement for each child text node.
-  for (auto* child : root_node->children()) {
-    ComPtr<IRawElementProviderSimple> text_node_raw =
-        QueryInterfaceFromNode<IRawElementProviderSimple>(child);
+  ComPtr<IRawElementProviderSimple> link_node_raw =
+      QueryInterfaceFromNode<IRawElementProviderSimple>(link_node);
+  ComPtr<IRawElementProviderSimple> inline_text_node_raw1 =
+      QueryInterfaceFromNode<IRawElementProviderSimple>(inline_text_node1);
+  ComPtr<IRawElementProviderSimple> inline_text_node_raw2 =
+      QueryInterfaceFromNode<IRawElementProviderSimple>(inline_text_node2);
 
-    ComPtr<ITextProvider> text_provider;
-    EXPECT_HRESULT_SUCCEEDED(
-        text_node_raw->GetPatternProvider(UIA_TextPatternId, &text_provider));
+  // Test GetEnclosingElement for the two leaves text nodes. The enclosing
+  // element of the first one should be itself and the enclosing element for the
+  // text node that is grandchild of the link node should return the link node.
+  ComPtr<ITextProvider> text_provider;
+  EXPECT_HRESULT_SUCCEEDED(inline_text_node_raw1->GetPatternProvider(
+      UIA_TextPatternId, &text_provider));
 
-    ComPtr<ITextRangeProvider> text_range_provider;
-    EXPECT_HRESULT_SUCCEEDED(
-        text_provider->get_DocumentRange(&text_range_provider));
+  ComPtr<ITextRangeProvider> text_range_provider;
+  EXPECT_HRESULT_SUCCEEDED(
+      text_provider->get_DocumentRange(&text_range_provider));
 
-    ComPtr<IRawElementProviderSimple> enclosing_element;
-    EXPECT_HRESULT_SUCCEEDED(
-        text_range_provider->GetEnclosingElement(&enclosing_element));
-    EXPECT_EQ(text_node_raw.Get(), enclosing_element.Get());
-  }
+  ComPtr<IRawElementProviderSimple> enclosing_element;
+  EXPECT_HRESULT_SUCCEEDED(
+      text_range_provider->GetEnclosingElement(&enclosing_element));
+  EXPECT_EQ(inline_text_node_raw1.Get(), enclosing_element.Get());
+
+  EXPECT_HRESULT_SUCCEEDED(inline_text_node_raw2->GetPatternProvider(
+      UIA_TextPatternId, &text_provider));
+
+  EXPECT_HRESULT_SUCCEEDED(
+      text_provider->get_DocumentRange(&text_range_provider));
+
+  EXPECT_HRESULT_SUCCEEDED(
+      text_range_provider->GetEnclosingElement(&enclosing_element));
+  EXPECT_EQ(link_node_raw.Get(), enclosing_element.Get());
 }
 
 TEST_F(AXPlatformNodeTextRangeProviderTest,
diff --git a/ui/accessibility/platform/ax_platform_node_win.cc b/ui/accessibility/platform/ax_platform_node_win.cc
index 1987b8b..729aaf2 100644
--- a/ui/accessibility/platform/ax_platform_node_win.cc
+++ b/ui/accessibility/platform/ax_platform_node_win.cc
@@ -6470,6 +6470,34 @@
   }
 }
 
+bool AXPlatformNodeWin::IsInaccessibleDueToAncestor() const {
+  AXPlatformNodeWin* parent = static_cast<AXPlatformNodeWin*>(
+      AXPlatformNode::FromNativeViewAccessible(GetParent()));
+  while (parent) {
+    if (parent->ShouldHideChildren())
+      return true;
+    parent = static_cast<AXPlatformNodeWin*>(
+        FromNativeViewAccessible(parent->GetParent()));
+  }
+  return false;
+}
+
+bool AXPlatformNodeWin::ShouldHideChildren() const {
+  switch (GetData().role) {
+    case ax::mojom::Role::kButton:
+    case ax::mojom::Role::kImage:
+    case ax::mojom::Role::kGraphicsSymbol:
+    case ax::mojom::Role::kLink:
+    case ax::mojom::Role::kMath:
+    case ax::mojom::Role::kProgressIndicator:
+    case ax::mojom::Role::kScrollBar:
+    case ax::mojom::Role::kSlider:
+      return true;
+    default:
+      return false;
+  }
+}
+
 base::string16 AXPlatformNodeWin::GetValue() const {
   base::string16 value = AXPlatformNodeBase::GetValue();
 
@@ -7199,6 +7227,23 @@
   }
 }
 
+AXPlatformNodeWin* AXPlatformNodeWin::GetLowestAccessibleElement() {
+  if (!IsInaccessibleDueToAncestor())
+    return this;
+
+  AXPlatformNodeWin* parent = static_cast<AXPlatformNodeWin*>(
+      AXPlatformNode::FromNativeViewAccessible(GetParent()));
+  while (parent) {
+    if (parent->ShouldHideChildren())
+      return parent;
+    parent = static_cast<AXPlatformNodeWin*>(
+        AXPlatformNode::FromNativeViewAccessible(parent->GetParent()));
+  }
+
+  NOTREACHED();
+  return nullptr;
+}
+
 void AXPlatformNodeWin::SanitizeTextAttributeValue(const std::string& input,
                                                    std::string* output) const {
   SanitizeStringAttributeForIA2(input, output);
diff --git a/ui/accessibility/platform/ax_platform_node_win.h b/ui/accessibility/platform/ax_platform_node_win.h
index e72d29f..92ce575 100644
--- a/ui/accessibility/platform/ax_platform_node_win.h
+++ b/ui/accessibility/platform/ax_platform_node_win.h
@@ -1032,6 +1032,9 @@
   // Helper to recursively find live-regions and fire a change event on them
   void FireLiveRegionChangeRecursive();
 
+  // Returns the parent node that makes this node inaccessible.
+  AXPlatformNodeWin* GetLowestAccessibleElement();
+
   // Convert a mojo event to an MSAA event. Exposed for testing.
   static base::Optional<DWORD> MojoEventToMSAAEvent(ax::mojom::Event event);
 
@@ -1071,6 +1074,10 @@
 
   base::Optional<LONG> ComputeUIALandmarkType() const;
 
+  bool IsInaccessibleDueToAncestor() const;
+
+  bool ShouldHideChildren() const;
+
   // AXPlatformNodeBase overrides.
   void Dispose() override;
 
diff --git a/ui/ozone/platform/scenic/sysmem_buffer_collection.cc b/ui/ozone/platform/scenic/sysmem_buffer_collection.cc
index 07c12db..1a26bd1 100644
--- a/ui/ozone/platform/scenic/sysmem_buffer_collection.cc
+++ b/ui/ozone/platform/scenic/sysmem_buffer_collection.cc
@@ -320,18 +320,16 @@
       break;
 
     case fuchsia::sysmem::ColorSpaceType::REC709: {
-      VkFormatFeatureFlags format_features =
-          VK_FORMAT_FEATURE_COSITED_CHROMA_SAMPLES_BIT |
-          VK_FORMAT_FEATURE_MIDPOINT_CHROMA_SAMPLES_BIT |
-          VK_FORMAT_FEATURE_SAMPLED_IMAGE_YCBCR_CONVERSION_LINEAR_FILTER_BIT;
-
       // Currently sysmem doesn't specify location of chroma samples relative to
-      // luma (see MTWN-397). Assume they are cosited with luma.
+      // luma (see fxb/13677). Assume they are cosited with luma. YCbCr info
+      // here must match the values passed for the same buffer in
+      // FuchsiaVideoDecoder. |format_features| are resolved later in the GPU
+      // process before the ycbcr info is passed to Skia.
       *ycbcr_info = gpu::VulkanYCbCrInfo(
           vk_image_info->format, /*external_format=*/0,
           VK_SAMPLER_YCBCR_MODEL_CONVERSION_YCBCR_709,
           VK_SAMPLER_YCBCR_RANGE_ITU_NARROW, VK_CHROMA_LOCATION_COSITED_EVEN,
-          VK_CHROMA_LOCATION_COSITED_EVEN, format_features);
+          VK_CHROMA_LOCATION_COSITED_EVEN, /*format_features=*/0);
       break;
     }
 
diff --git a/ui/views/controls/separator.cc b/ui/views/controls/separator.cc
index 54440d23..325ba7e 100644
--- a/ui/views/controls/separator.cc
+++ b/ui/views/controls/separator.cc
@@ -54,10 +54,6 @@
   return size;
 }
 
-void Separator::GetAccessibleNodeData(ui::AXNodeData* node_data) {
-  node_data->role = ax::mojom::Role::kSplitter;
-}
-
 void Separator::OnPaint(gfx::Canvas* canvas) {
   SkColor color = overridden_color_
                       ? *overridden_color_
diff --git a/ui/views/controls/separator.h b/ui/views/controls/separator.h
index f547479..2d28e40 100644
--- a/ui/views/controls/separator.h
+++ b/ui/views/controls/separator.h
@@ -33,7 +33,6 @@
 
   // Overridden from View:
   gfx::Size CalculatePreferredSize() const override;
-  void GetAccessibleNodeData(ui::AXNodeData* node_data) override;
   void OnPaint(gfx::Canvas* canvas) override;
 
  private:
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
index 519a6e1..efdf0d81 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -26,6 +26,7 @@
 #include "ui/base/class_property.h"
 #include "ui/base/hit_test.h"
 #include "ui/base/ime/input_method.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/compositor/layer.h"
 #include "ui/gfx/canvas.h"
 #include "ui/gfx/geometry/point_conversions.h"
@@ -99,6 +100,13 @@
     init_params.type = full_screen ? Widget::InitParams::TYPE_WINDOW
                                    : is_menu ? Widget::InitParams::TYPE_MENU
                                              : Widget::InitParams::TYPE_POPUP;
+#if defined(OS_WIN)
+    // For menus, on Windows versions that support drop shadow remove
+    // the standard frame in order to keep just the shadow.
+    if (::features::IsFormControlsRefreshEnabled() &&
+        init_params.type == Widget::InitParams::TYPE_MENU)
+      init_params.remove_standard_frame = true;
+#endif
     init_params.bounds = bounds;
     init_params.ownership = Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET;
     init_params.layer_type = ui::LAYER_NOT_DRAWN;
diff --git a/ui/views/widget/widget_hwnd_utils.cc b/ui/views/widget/widget_hwnd_utils.cc
index 9edfa2c..e26193b 100644
--- a/ui/views/widget/widget_hwnd_utils.cc
+++ b/ui/views/widget/widget_hwnd_utils.cc
@@ -9,6 +9,7 @@
 #include "base/command_line.h"
 #include "build/build_config.h"
 #include "ui/base/l10n/l10n_util_win.h"
+#include "ui/base/ui_base_features.h"
 #include "ui/base/ui_base_switches.h"
 #include "ui/views/widget/widget_delegate.h"
 #include "ui/views/win/hwnd_message_handler.h"
@@ -108,6 +109,15 @@
       break;
     case Widget::InitParams::TYPE_MENU:
       *style |= WS_POPUP;
+      if (::features::IsFormControlsRefreshEnabled() &&
+          params.remove_standard_frame) {
+        // If the platform doesn't support drop shadow, decorate the Window
+        // with just a border.
+        if (ui::win::IsAeroGlassEnabled())
+          *style |= WS_THICKFRAME;
+        else
+          *style |= WS_BORDER;
+      }
       break;
     case Widget::InitParams::TYPE_TOOLTIP:
       *style |= WS_POPUP;
diff --git a/ui/wm/core/window_util.cc b/ui/wm/core/window_util.cc
index e9edfc93..c98165c 100644
--- a/ui/wm/core/window_util.cc
+++ b/ui/wm/core/window_util.cc
@@ -152,9 +152,9 @@
 
 std::unique_ptr<ui::LayerTreeOwner> RecreateLayers(ui::LayerOwner* root) {
   DCHECK(root->OwnsLayer());
-  return RecreateLayersWithClosure(root, base::Bind([](ui::LayerOwner* owner) {
-                                     return owner->RecreateLayer();
-                                   }));
+  return RecreateLayersWithClosure(
+      root, base::BindRepeating(
+                [](ui::LayerOwner* owner) { return owner->RecreateLayer(); }));
 }
 
 std::unique_ptr<ui::LayerTreeOwner> RecreateLayersWithClosure(